Skip to content

Commit

Permalink
fix(datepicker): handle collapsed days/weeks properly
Browse files Browse the repository at this point in the history
Fixes #1377

Closes #1383
  • Loading branch information
maxokorokov authored and pkozlowski-opensource committed Mar 17, 2017
1 parent fb1678c commit 4f54bfa
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 30 deletions.
78 changes: 69 additions & 9 deletions src/datepicker/datepicker-month-view.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,28 +181,59 @@ describe('ngb-datepicker-month-view', () => {
}

it('should apply proper visibility to other months days', () => {
const fixture = createTestComponent(
'<ngb-datepicker-month-view [month]="month" [outsideDays]="outsideDays"></ngb-datepicker-month-view>');
const fixture = createTestComponent(`
<template #tpl let-date="date">{{ date.day }}</template>
<ngb-datepicker-month-view [month]="month" [outsideDays]="outsideDays" [dayTemplate]="tpl"></ngb-datepicker-month-view>
`);

let dates = getDates(fixture.nativeElement);
expect(dates[0]).not.toHaveCssClass('hidden');
expect(dates[0]).not.toHaveCssClass('collapsed');
expect(dates[1]).not.toHaveCssClass('hidden');
expect(dates[1]).not.toHaveCssClass('collapsed');
expectDates(fixture.nativeElement, ['22', '23']);

fixture.componentInstance.outsideDays = 'collapsed';
fixture.detectChanges();
expect(dates[0]).not.toHaveCssClass('hidden');
expect(dates[0]).not.toHaveCssClass('collapsed');
expect(dates[1]).not.toHaveCssClass('hidden');
expect(dates[1]).toHaveCssClass('collapsed');
expect(dates[1]).toHaveCssClass('hidden');
expectDates(fixture.nativeElement, ['22', '']);

fixture.componentInstance.outsideDays = 'hidden';
fixture.detectChanges();
expect(dates[0]).not.toHaveCssClass('hidden');
expect(dates[0]).not.toHaveCssClass('collapsed');
expect(dates[1]).toHaveCssClass('hidden');
expect(dates[1]).not.toHaveCssClass('collapsed');
expectDates(fixture.nativeElement, ['22', '']);
});

it('should collapse weeks outside of current month', () => {
const fixture = createTestComponent(`
<template #tpl let-date="date">{{ date.day }}</template>
<ngb-datepicker-month-view [month]="monthCollapsedWeeks" [outsideDays]="outsideDays" [dayTemplate]="tpl">
</ngb-datepicker-month-view>
`);

expectDates(fixture.nativeElement, ['4', '1', '2', '3', '4', '1', '2', '3']);

fixture.componentInstance.outsideDays = 'collapsed';
fixture.detectChanges();
expectDates(fixture.nativeElement, ['', '1', '2', '3', '4', '']);

fixture.componentInstance.outsideDays = 'hidden';
fixture.detectChanges();
expectDates(fixture.nativeElement, ['', '1', '2', '3', '4', '', '', '']);
});

it('should collapse weeks regardless of "showWeekNumbers" value', () => {
const fixture = createTestComponent(`
<template #tpl let-date="date">{{ date.day }}</template>
<ngb-datepicker-month-view [month]="monthCollapsedWeeks" outsideDays="collapsed" [dayTemplate]="tpl">
</ngb-datepicker-month-view>
`);

expectDates(fixture.nativeElement, ['', '1', '2', '3', '4', '']);

fixture.componentInstance.showWeekNumbers = true;
fixture.detectChanges();
expectDates(fixture.nativeElement, ['', '1', '2', '3', '4', '']);
});

});
Expand All @@ -220,6 +251,35 @@ class TestComponent {
}]
};

monthCollapsedWeeks: MonthViewModel = {
firstDate: new NgbDate(2016, 8, 1),
year: 2016,
number: 8,
weekdays: [1, 2],
weeks: [
// month: 7, 8
{
number: 2,
days: [{date: new NgbDate(2016, 7, 4), disabled: false}, {date: new NgbDate(2016, 8, 1), disabled: false}]
},
// month: 8, 8
{
number: 3,
days: [{date: new NgbDate(2016, 8, 2), disabled: false}, {date: new NgbDate(2016, 8, 3), disabled: false}]
},
// month: 8, 9
{
number: 3,
days: [{date: new NgbDate(2016, 8, 4), disabled: false}, {date: new NgbDate(2016, 9, 1), disabled: false}]
},
// month: 9, 9 -> to collapse
{
number: 4,
days: [{date: new NgbDate(2016, 9, 2), disabled: false}, {date: new NgbDate(2016, 9, 3), disabled: false}]
}
]
};

showWeekdays = true;
showWeekNumbers = true;
outsideDays = 'visible';
Expand Down
45 changes: 24 additions & 21 deletions src/datepicker/datepicker-month-view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component, Input, TemplateRef, Output, EventEmitter} from '@angular/core';
import {MonthViewModel, DayViewModel} from './datepicker-view-model';
import {MonthViewModel, DayViewModel, WeekViewModel} from './datepicker-view-model';
import {NgbDate} from './ngb-date';
import {NgbDatepickerI18n} from './datepicker-i18n';
import {DayTemplateContext} from './datepicker-day-template-context';
Expand All @@ -18,15 +18,9 @@ import {DayTemplateContext} from './datepicker-day-template-context';
.ngb-dp-day {
cursor: pointer;
}
.ngb-dp-day.disabled, .ngb-dp-day.hidden, .ngb-dp-day.collapsed {
.ngb-dp-day.disabled, .ngb-dp-day.hidden {
cursor: default;
}
:host/deep/.ngb-dp-day.collapsed > * {
display: none;
}
:host/deep/.ngb-dp-day.hidden > * {
visibility: hidden;
}
`],
template: `
<div *ngIf="showWeekdays" class="ngb-dp-week d-flex">
Expand All @@ -35,18 +29,22 @@ import {DayTemplateContext} from './datepicker-day-template-context';
{{ i18n.getWeekdayShortName(w) }}
</div>
</div>
<div *ngFor="let week of month.weeks" class="ngb-dp-week d-flex">
<div *ngIf="showWeekNumbers" class="ngb-dp-week-number small text-center font-italic text-muted">{{ week.number }}</div>
<div *ngFor="let day of week.days" (click)="doSelect(day)" class="ngb-dp-day" [class.disabled]="isDisabled(day)"
[class.collapsed]="isCollapsed(day)" [class.hidden]="isHidden(day)">
<template [ngTemplateOutlet]="dayTemplate"
[ngOutletContext]="{date: {year: day.date.year, month: day.date.month, day: day.date.day},
currentMonth: month.number,
disabled: isDisabled(day),
selected: isSelected(day.date)}">
<template ngFor let-week [ngForOf]="month.weeks">
<div *ngIf="!isCollapsed(week)" class="ngb-dp-week d-flex">
<div *ngIf="showWeekNumbers" class="ngb-dp-week-number small text-center font-italic text-muted">{{ week.number }}</div>
<div *ngFor="let day of week.days" (click)="doSelect(day)" class="ngb-dp-day" [class.disabled]="isDisabled(day)"
[class.hidden]="isHidden(day)">
<template [ngIf]="!isHidden(day)">
<template [ngTemplateOutlet]="dayTemplate"
[ngOutletContext]="{date: {year: day.date.year, month: day.date.month, day: day.date.day},
currentMonth: month.number,
disabled: isDisabled(day),
selected: isSelected(day.date)}">
</template>
</template>
</div>
</div>
</div>
</template>
`
})
export class NgbDatepickerMonthView {
Expand All @@ -63,7 +61,7 @@ export class NgbDatepickerMonthView {
constructor(public i18n: NgbDatepickerI18n) {}

doSelect(day: DayViewModel) {
if (!this.isDisabled(day) && !this.isCollapsed(day) && !this.isHidden(day)) {
if (!this.isDisabled(day) && !this.isHidden(day)) {
this.select.emit(NgbDate.from(day.date));
}
}
Expand All @@ -72,7 +70,12 @@ export class NgbDatepickerMonthView {

isSelected(date: NgbDate) { return this.selectedDate && this.selectedDate.equals(date); }

isCollapsed(day: DayViewModel) { return this.outsideDays === 'collapsed' && this.month.number !== day.date.month; }
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;
}

isHidden(day: DayViewModel) { return this.outsideDays === 'hidden' && this.month.number !== day.date.month; }
isHidden(day: DayViewModel) {
return (this.outsideDays === 'hidden' || this.outsideDays === 'collapsed') && this.month.number !== day.date.month;
}
}

0 comments on commit 4f54bfa

Please sign in to comment.