Skip to content

Commit

Permalink
feat(datepicker): initial version of datepicker component (#618)
Browse files Browse the repository at this point in the history
Closes #20
  • Loading branch information
maxokorokov committed Sep 2, 2016
1 parent 1c290a2 commit 9e8c5c0
Show file tree
Hide file tree
Showing 34 changed files with 1,720 additions and 5 deletions.
2 changes: 2 additions & 0 deletions demo/src/app/app.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
NgbdButtons,
NgbdCarousel,
NgbdCollapse,
NgbdDatepicker,
NgbdDropdown,
NgbdModal,
NgbdPagination,
Expand All @@ -29,6 +30,7 @@ const routes: Routes = [
{path: 'components/buttons', component: NgbdButtons},
{path: 'components/carousel', component: NgbdCarousel},
{path: 'components/collapse', component: NgbdCollapse},
{path: 'components/datepicker', component: NgbdDatepicker},
{path: 'components/dropdown', component: NgbdDropdown},
{path: 'components/modal', component: NgbdModal},
{path: 'components/pagination', component: NgbdPagination},
Expand Down
18 changes: 18 additions & 0 deletions demo/src/app/components/datepicker/datepicker.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {Component} from '@angular/core';
import {DEMO_SNIPPETS} from './demos';

@Component({
selector: 'ngbd-datepicker',
template: `
<ngbd-content-wrapper component="Datepicker">
<ngbd-api-docs directive="NgbDatepicker"></ngbd-api-docs>
<ngbd-api-docs-class type="DayTemplateContext"></ngbd-api-docs-class>
<ngbd-example-box demoTitle="Basic datepicker" [htmlSnippet]="snippets.basic.markup" [tsSnippet]="snippets.basic.code">
<ngbd-datepicker-basic></ngbd-datepicker-basic>
</ngbd-example-box>
</ngbd-content-wrapper>
`
})
export class NgbdDatepicker {
snippets = DEMO_SNIPPETS;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<p>Simple datepicker</p>

<ngb-datepicker #dp [(ngModel)]="model"></ngb-datepicker>

<hr/>

<button class="btn btn-sm btn-outline-primary" (click)="selectToday()">Select Today</button>
<button class="btn btn-sm btn-outline-primary" (click)="dp.navigateTo()">To current month</button>
<button class="btn btn-sm btn-outline-primary" (click)="dp.navigateTo({year: 2013, month: 1})">To Feb 2013</button>

<hr/>

<pre>Model: {{ model | json }}</pre>
16 changes: 16 additions & 0 deletions demo/src/app/components/datepicker/demos/basic/datepicker-basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {Component} from '@angular/core';

const now = new Date();

@Component({
selector: 'ngbd-datepicker-basic',
templateUrl: './datepicker-basic.html'
})
export class NgbdDatepickerBasic {

model;

selectToday() {
this.model = {year: now.getFullYear(), month: now.getMonth(), day: now.getDate()};
}
}
9 changes: 9 additions & 0 deletions demo/src/app/components/datepicker/demos/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {NgbdDatepickerBasic} from './basic/datepicker-basic';

export const DEMO_DIRECTIVES = [NgbdDatepickerBasic];

export const DEMO_SNIPPETS = {
basic: {
code: require('!!prismjs?lang=typescript!./basic/datepicker-basic'),
markup: require('!!prismjs?lang=markup!./basic/datepicker-basic.html')}
};
14 changes: 14 additions & 0 deletions demo/src/app/components/datepicker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export * from './datepicker.component';

import {NgModule} from '@angular/core';
import {NgbdSharedModule} from '../../shared';
import {NgbdComponentsSharedModule} from '../shared';
import {NgbdDatepicker} from './datepicker.component';
import {DEMO_DIRECTIVES} from './demos';

@NgModule({
imports: [NgbdSharedModule, NgbdComponentsSharedModule],
exports: [NgbdDatepicker],
declarations: [NgbdDatepicker, ...DEMO_DIRECTIVES]
})
export class NgbdDatepickerModule {}
4 changes: 4 additions & 0 deletions demo/src/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './alert';
export * from './buttons';
export * from './carousel';
export * from './collapse';
export * from './datepicker';
export * from './dropdown';
export * from './modal';
export * from './pagination';
Expand All @@ -23,6 +24,7 @@ import {NgbdAlertModule} from './alert';
import {NgbdButtonsModule} from './buttons';
import {NgbdCarouselModule} from './carousel';
import {NgbdCollapseModule} from './collapse';
import {NgbdDatepickerModule} from './datepicker';
import {NgbdDropdownModule} from './dropdown';
import {NgbdModalModule} from './modal';
import {NgbdPaginationModule} from './pagination';
Expand All @@ -42,6 +44,7 @@ import {NgbdTypeaheadModule} from './typeahead';
NgbdButtonsModule,
NgbdCarouselModule,
NgbdCollapseModule,
NgbdDatepickerModule,
NgbdDropdownModule,
NgbdModalModule,
NgbdPaginationModule,
Expand All @@ -59,6 +62,7 @@ import {NgbdTypeaheadModule} from './typeahead';
NgbdButtonsModule,
NgbdCarouselModule,
NgbdCollapseModule,
NgbdDatepickerModule,
NgbdDropdownModule,
NgbdModalModule,
NgbdPaginationModule,
Expand Down
1 change: 1 addition & 0 deletions demo/src/app/shared/side-nav/side-nav.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class SideNavComponent {
'Buttons',
'Carousel',
'Collapse',
'Datepicker',
'Dropdown',
'Modal',
'Pagination',
Expand Down
24 changes: 24 additions & 0 deletions src/datepicker/datepicker-day-template-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Context for the datepicker 'day' template in case you want to override the default one
*/
export interface DayTemplateContext {
/**
* Month currently displayed by the datepicker
*/
currentMonth: number;

/**
* Date that corresponds to the template
*/
date: {year: number, month: number, day: number};

/**
* True if current date is disabled
*/
disabled: boolean;

/**
* True if current date is selected
*/
selected: boolean;
}
77 changes: 77 additions & 0 deletions src/datepicker/datepicker-day-view.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {TestBed} from '@angular/core/testing';

import {Component} from '@angular/core';
import {NgbDatepickerModule} from './datepicker.module';
import {NgbDatepickerDayView} from './datepicker-day-view';

function getElement(element: HTMLElement): HTMLElement {
return <HTMLElement>element.querySelector('[ngbDatepickerDayView]');
}

describe('ngbDatepickerDayView', () => {

beforeEach(() => {
TestBed.overrideModule(NgbDatepickerModule, {set: {exports: [NgbDatepickerDayView]}});
TestBed.configureTestingModule({declarations: [TestComponent], imports: [NgbDatepickerModule]});
});

it('should display date', () => {
const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

const el = getElement(fixture.nativeElement);
expect(el.innerText).toBe('22');

fixture.componentInstance.date = {year: 2016, month: 7, day: 25};
fixture.detectChanges();
expect(el.innerText).toBe('25');
});

it('should apply text-muted style for disabled days', () => {
const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

const el = getElement(fixture.nativeElement);
expect(el).not.toHaveCssClass('text-muted');

fixture.componentInstance.disabled = true;
fixture.detectChanges();
expect(el).toHaveCssClass('text-muted');
});

it('should apply text-muted style for days of a different month', () => {
const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

const el = getElement(fixture.nativeElement);
expect(el).not.toHaveCssClass('text-muted');

fixture.componentInstance.date = {year: 2016, month: 8, day: 22};
fixture.detectChanges();
expect(el).toHaveCssClass('text-muted');
});

it('should apply selected style', () => {
const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

const el = getElement(fixture.nativeElement);
expect(el).not.toHaveCssClass('bg-primary');

fixture.componentInstance.selected = true;
fixture.detectChanges();
expect(el).toHaveCssClass('bg-primary');
});
});

@Component({
selector: 'test-cmp',
template:
'<div ngbDatepickerDayView [date]="date" [currentMonth]="currentMonth" [selected]="selected" [disabled]="disabled"></div>'
})
class TestComponent {
currentMonth = 7;
date = {year: 2016, month: 7, day: 22};
disabled = false;
selected = false;
}
22 changes: 22 additions & 0 deletions src/datepicker/datepicker-day-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {Component, Input} from '@angular/core';

@Component({
selector: '[ngbDatepickerDayView]',
styles: [`
:host {
text-align: center;
padding: 0.185rem 0.25rem;
border-radius: 0.25rem;
}
`],
host: {'[class.bg-primary]': 'selected', '[class.text-muted]': 'isMuted()'},
template: `{{ date.day }}`
})
export class NgbDatepickerDayView {
@Input() currentMonth: number;
@Input() date: {year: number, month: number, day: number};
@Input() disabled: boolean;
@Input() selected: boolean;

isMuted() { return this.date.month !== this.currentMonth || this.disabled; }
}
19 changes: 19 additions & 0 deletions src/datepicker/datepicker-i18n.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {NgbDatepickerI18nDefault} from './datepicker-i18n';

describe('ngb-datepicker-i18n-default', () => {

const i18n = new NgbDatepickerI18nDefault();

it('should return month name', () => {
expect(i18n.getMonthName(0)).toBe('Jan');
expect(i18n.getMonthName(11)).toBe('Dec');
expect(i18n.getMonthName(12)).toBe(undefined);
});

it('should return weekday name', () => {
expect(i18n.getWeekdayName(0)).toBe('Su');
expect(i18n.getWeekdayName(6)).toBe('Sa');
expect(i18n.getWeekdayName(7)).toBe(undefined);
});

});
17 changes: 17 additions & 0 deletions src/datepicker/datepicker-i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {Injectable} from '@angular/core';

const WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

@Injectable()
export abstract class NgbDatepickerI18n {
abstract getWeekdayName(weekday: number): string;
abstract getMonthName(month: number): string;
}

@Injectable()
export class NgbDatepickerI18nDefault extends NgbDatepickerI18n {
getWeekdayName(weekday: number): string { return WEEKDAYS[weekday]; }

getMonthName(month: number): string { return MONTHS[month]; }
}

0 comments on commit 9e8c5c0

Please sign in to comment.