Skip to content

Commit

Permalink
Calendar multi view mode (#5666)
Browse files Browse the repository at this point in the history
* feat(calendar): calendar multi view #4282
  • Loading branch information
hanastasov authored and zdrawku committed Sep 17, 2019
1 parent cb16744 commit 194a4cf
Show file tree
Hide file tree
Showing 18 changed files with 719 additions and 201 deletions.
18 changes: 16 additions & 2 deletions projects/igniteui-angular/src/lib/calendar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ A multiple selection calendar with different locale and templating for the subhe
</igx-calendar>
```

A calendar displaying more than one month in the view and hiding the days that are outside of the current month
```html
<igx-calendar monthsViewNumber="2" [hideOutsideDays]="'true'">
</igx-calendar>
```

The **igxCalendar** implements the `ControlValueAccessor` interface, providing two-way data-binding
and the expected behavior when used both in Template-driven or Reactive Forms.

Expand All @@ -65,8 +71,8 @@ When the **igxCalendar** component is focused:
- `PageDown` will move to the next month.
- `Shift + PageUp` will move to the previous year.
- `Shift + PageDown` will move to the next year.
- `Home` will focus the first day of the current month that is into view.
- `End` will focus the last day of the current month that is into view.
- `Home` will focus the first day of the current month (or first month if more months are displayed) hat is into view.
- `End` will focus the last day of the current month ((or last month if more months are displayed)) that is into view.
- `Tab` will navigate through the subheader buttons;

When `prev` or `next` month buttons (in the subheader) are focused:
Expand All @@ -82,6 +88,7 @@ When a day inside the current month is focused:
- Arrow keys will navigate through the days.
- Arrow keys will allow navigation to previous/next month as well.
- `Enter` will select the currently focused day.
- When more than one month view is displayed, navigating with the arrow keys should move to next/previous month after navigating from first/last day in current month.

When a month inside the months view is focused:
- Arrow keys will navigate through the months.
Expand Down Expand Up @@ -154,6 +161,13 @@ The default values are listed below.
{ day: false, month: true, year: false }
```

- `monthViewsNumber: number`
Controls the number of month views displayed. Default is 1.

- `hideOusideDays: boolean`
Controls the visibility of the dates that do not belong to the current month.


### Outputs

- `onSelection(): Date | Date[]`
Expand Down
29 changes: 27 additions & 2 deletions projects/igniteui-angular/src/lib/calendar/calendar-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ export class IgxCalendarBase implements ControlValueAccessor {
* Otherwise it is an array of `Date` objects.
*/
public set value(value: Date | Date[]) {
if (!value || !!value && (value as Date[]).length === 0) {
return;
}

this.selectDate(value);
}

Expand Down Expand Up @@ -210,6 +214,20 @@ export class IgxCalendarBase implements ControlValueAccessor {
this._specialDates = value;
}

/**
* Sets/gets whether the outside dates (dates that are out of the current month) will be hidden.
* Default value is `false`.
* ```html
* <igx-calendar [hideOutsideDays] = "true"></igx-calendar>
* ```
* ```typescript
* let hideOutsideDays = this.calendar.hideOutsideDays;
* ```
*/

@Input()
public hideOutsideDays = false;

/**
* Emits an event when a date is selected.
* Provides reference the `selectedDates` property.
Expand Down Expand Up @@ -379,7 +397,14 @@ export class IgxCalendarBase implements ControlValueAccessor {
*/
private selectMultiple(value: Date | Date[]) {
if (Array.isArray(value)) {
this.selectedDates = this.selectedDates.concat(value.map(v => this.getDateOnly(v)));
const newDates = value.map(v => this.getDateOnly(v).getTime());
const selDates = this.selectedDates.map(v => this.getDateOnly(v).getTime());

if (JSON.stringify(newDates) === JSON.stringify(selDates)) {
return;
}

this.selectedDates = Array.from(new Set([...newDates, ...selDates])).map(v => new Date(v));
} else {
const valueDateOnly = this.getDateOnly(value);
const newSelection = [];
Expand All @@ -395,7 +420,7 @@ export class IgxCalendarBase implements ControlValueAccessor {
this.selectedDates = this.selectedDates.concat(newSelection);
}
}

this.selectedDates.sort((a: Date, b: Date) => a.valueOf() - b.valueOf());
this._onChangeCallback(this.selectedDates);
}

Expand Down
53 changes: 31 additions & 22 deletions projects/igniteui-angular/src/lib/calendar/calendar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
<span>{{ getFormattedDate().monthday }}</span>
</ng-template>

<ng-template let-result #defaultMonth>
<ng-template let-result #defaultMonth let-obj>
<span tabindex="0" #monthsBtn (keydown)="activeViewYearKB($event)" (click)="activeViewYear()"
class="igx-calendar-picker__date">
{{ formattedMonth(viewDate) }}
{{ formattedMonth(getViewDate(obj.index)) }}
</span>
<span tabindex="0" #yearsBtn (keydown)="activeViewDecadeKB($event)" (click)="activeViewDecade()"
class="igx-calendar-picker__date">
{{ formattedYear(viewDate) }}
{{ formattedYear(getViewDate(obj.index)) }}
</span>
</ng-template>

Expand All @@ -26,33 +26,42 @@ <h2 class="igx-calendar__header-date">
(swipeleft)="nextMonth()">
<div class="igx-calendar-picker">
<div tabindex="0" class="igx-calendar-picker__prev" #prevMonthBtn
igxCalendarScrollMonth [startScroll]="startPrevMonthScroll" [stopScroll]="stopMonthScroll">
igxCalendarScrollMonth [startScroll]="startPrevMonthScroll" [stopScroll]="stopMonthScroll" [ngStyle]="{
'min-width.%': 100/(monthsViewNumber*7),
'left': 0
}">
<igx-icon fontSet="material">keyboard_arrow_left</igx-icon>
</div>
<div>
<ng-container *ngTemplateOutlet="subheaderTemplate ? subheaderTemplate : defaultMonth; context: context">
<div *ngFor="let view of dayViews; index as i;" [style.width.%]="100/monthsViewNumber">
<ng-container *ngTemplateOutlet="subheaderTemplate ? subheaderTemplate : defaultMonth; context: getContext(i)">
</ng-container>
</div>
<div tabindex="0" class="igx-calendar-picker__next" #nextMonthBtn
igxCalendarScrollMonth [startScroll]="startNextMonthScroll" [stopScroll]="stopMonthScroll">
<div tabindex="0" class="igx-calendar-picker__next" #nextMonthBtn
igxCalendarScrollMonth [startScroll]="startNextMonthScroll" [stopScroll]="stopMonthScroll" [ngStyle]="{
'min-width.%': 100/(monthsViewNumber*7),
'right': 0
}">
<igx-icon fontSet="material">keyboard_arrow_right</igx-icon>
</div>
</div>

<igx-days-view [changeDaysView]="true" #days
[animationAction]="monthAction"
[locale]="locale"
[value]="value"
[viewDate]="viewDate"
[weekStart]="weekStart"
[formatOptions]="formatOptions"
[formatViews]="formatViews"
[selection]="selection"
[disabledDates]="disabledDates"
[specialDates]="specialDates"
(onViewChanged)="viewChanged($event)"
(onDateSelection)="childClicked($event)">
</igx-days-view>
<div style="display: flex">
<igx-days-view *ngFor="let view of dayViews; index as i;" [changeDaysView]="true" #days
[animationAction]="monthAction"
[locale]="locale"
[value]="value"
[viewDate]="getViewDate(i)"
[weekStart]="weekStart"
[formatOptions]="formatOptions"
[formatViews]="formatViews"
[selection]="selection"
[disabledDates]="disabledDates"
[specialDates]="specialDates"
[hideOutsideDays]="hideOutsideDays"
(onViewChanged)="viewChanged($event)"
(onDateSelection)="childClicked($event)">
</igx-days-view>
</div>
</div>

<igx-months-view *ngIf="isYearView" [@animateView]="activeView" #months
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,6 @@ describe('IgxCalendar', () => {

selectedDates.forEach(d => {
expect(d.selected).toBe(true);
expect(d.isSelectedCSS).toBe(true);
});

const notSelectedDates = calendar.daysView.dates.toArray().filter(d => {
Expand All @@ -1051,7 +1050,6 @@ describe('IgxCalendar', () => {

notSelectedDates.forEach(d => {
expect(d.selected).toBe(false);
expect(d.isSelectedCSS).toBe(false);
});
});
});
Expand All @@ -1070,7 +1068,6 @@ describe('IgxCalendar', () => {

specialDates.forEach(d => {
expect(d.isSpecial).toBe(true);
expect(d.isSpecialCSS).toBe(true);
});

let disabledDates = calendar.daysView.dates.toArray().filter(d => {
Expand Down Expand Up @@ -1098,7 +1095,6 @@ describe('IgxCalendar', () => {

specialDates.forEach(d => {
expect(d.isSpecial).toBe(true);
expect(d.isSpecialCSS).toBe(true);
});

disabledDates = calendar.daysView.dates.toArray().filter(d => {
Expand Down Expand Up @@ -1804,6 +1800,8 @@ describe('IgxCalendar', () => {
fixture.detectChanges();

UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowLeft');
fixture.detectChanges();
await wait(400);
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowLeft');
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowLeft');
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowLeft');
Expand All @@ -1818,6 +1816,8 @@ describe('IgxCalendar', () => {
fixture.detectChanges();

UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowLeft');
fixture.detectChanges();
await wait(400);
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowLeft');
fixture.detectChanges();
await wait(400);
Expand Down Expand Up @@ -1851,6 +1851,8 @@ describe('IgxCalendar', () => {
fixture.detectChanges();

UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowDown');
fixture.detectChanges();
await wait(400);
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowDown');
fixture.detectChanges();
await wait(400);
Expand All @@ -1859,6 +1861,8 @@ describe('IgxCalendar', () => {
expect(date.nativeElement).toBe(document.activeElement);

UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowDown');
fixture.detectChanges();
await wait(400);
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowDown');
fixture.detectChanges();
await wait(400);
Expand Down Expand Up @@ -1892,6 +1896,8 @@ describe('IgxCalendar', () => {
fixture.detectChanges();

UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowDown');
fixture.detectChanges();
await wait(400);
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowRight');
UIInteractions.simulateKeyDownEvent(document.activeElement, 'ArrowRight');
fixture.detectChanges();
Expand Down Expand Up @@ -2060,7 +2066,6 @@ class DateTester {
static testDatesSpeciality(dates: IgxDayItemComponent[], special: boolean): void {
for (const date of dates) {
expect(date.isSpecial).toBe(special);
expect(date.isSpecialCSS).toBe(special);
}
}
}
Expand Down
Loading

0 comments on commit 194a4cf

Please sign in to comment.