diff --git a/demo/src/app/components/+datepicker/datepicker-section.component.ts b/demo/src/app/components/+datepicker/datepicker-section.component.ts index 8b69d7f72c..54bb949e3d 100644 --- a/demo/src/app/components/+datepicker/datepicker-section.component.ts +++ b/demo/src/app/components/+datepicker/datepicker-section.component.ts @@ -2,71 +2,151 @@ import { Component } from '@angular/core'; import { DEMOS } from './demos'; // webpack html imports +let oldTitleDoc = require('html-loader!markdown-loader!./docs/titleOld.md'); let titleDoc = require('html-loader!markdown-loader!./docs/title.md'); @Component({ selector: 'datepicker-section', - template: ` + template: ` -

Datepicker is a highly configurable component that adds datepicker functionality to your pages. You can - customize the date format and language, restrict the selectable date ranges.

- -

Contents

- -

Usage

+

Usage

+ +

+ +

Examples

+

Basic

+ +

BsDatepickerModule is activily developed but you can use it already

+

Notebale change is additional css for it "/datepicker/bs-datepicker.css"

+

There are two ways of adding css:

+ +

In nearest time will be added:

+ + +
+ +

Themes

+ +

Datepicker comes with some default color schemes. + You can change it by manipulating containerClass property in bsConfig object

+

There are 6 color schemes: theme-default, theme-green, theme-blue, + theme-dark-blue, theme-red, theme-orange

+ +
-

+

Locales

-

Examples

+ +

Datepicker can use different locales.
It's possible to change a locale by changing locale + property in bsConfig object, list of available locales is in dropdown below.

+

To use a different locale, you have to import it from ngx-bootstrap/bs-moment and define it + in your @NgModule using function defineLocale

+

Example:

+ import {{ '{' }} defineLocale {{ '}' }} from 'ngx-bootstrap/bs-moment';
+ import {{ '{' }} de {{ '}' }} from 'ngx-bootstrap/locale';
+ defineLocale('de', de)); +

+ +
- -

BsDatepickerModule is activily developed but you can use it already

-

Notebale change is additional css for it "/datepicker/bs-datepicker.css"

-

In nearest time will be added:

- - -
+

Min-max

+ +

You can set min and max date of datepicker/daterangepicker using minDate and maxDate properties

+

In the following example minDate is set to yesterday and maxDate to the current day in the next week

+ +
- - - - - - - +

Disabled (scratch, WIP)

+ +

If you want to disable datepicker set is isDisabled property to true

+ +
+ +

Forms

+ +

Datepicker and daterangepicker can be used in forms. Keep in mind that value of ngModel + is Date object (array of 2 object for daterangepicker)

+ +
+ +

Reactive forms

+ + + + +

API Reference

+ + + + +

This is a legacy version of datepicker without support of daterangepicker, locales, themes, etc.

+

Contents

+ + +

Usage

- - - +

+ +

Example

+ + + -

API Reference

- +

API Reference

+ +
+
` }) export class DatepickerSectionComponent { public name: string = 'Datepicker'; public src: string = 'https://github.com/valor-software/ngx-bootstrap/tree/development/src/datepicker'; public demos: any = DEMOS; + public oldTitleDoc: string = oldTitleDoc; public titleDoc: string = titleDoc; } diff --git a/demo/src/app/components/+datepicker/demo-datepicker.module.ts b/demo/src/app/components/+datepicker/demo-datepicker.module.ts index a8f0e8adb0..b78604affd 100644 --- a/demo/src/app/components/+datepicker/demo-datepicker.module.ts +++ b/demo/src/app/components/+datepicker/demo-datepicker.module.ts @@ -1,15 +1,16 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { DatepickerModule, BsDatepickerModule } from 'ngx-bootstrap/datepicker'; +import { TabsModule } from 'ngx-bootstrap/tabs'; import { SharedModule } from '../../shared'; import { DatepickerSectionComponent } from './datepicker-section.component'; import { DEMO_COMPONENTS } from './demos'; import { routes } from './demo-datepicker.routes'; -import { defineLocale, getSetGlobalLocale } from 'ngx-bootstrap/bs-moment'; +import { defineLocale } from 'ngx-bootstrap/bs-moment'; import { ar, de, enGb, es, esDo, esUs, fr, hi, it, ja, ko, nl, nlBe, pl, ptBr, ru, zhCn } from 'ngx-bootstrap/locale'; @@ -18,7 +19,6 @@ const locales = [ar, de, enGb, es, esDo, esUs, fr, hi, it, ja, ko, nl, nlBe, pl, locales.forEach(locale => defineLocale(locale.abbr, locale)); -getSetGlobalLocale('en'); @NgModule({ declarations: [ @@ -28,8 +28,10 @@ getSetGlobalLocale('en'); imports: [ DatepickerModule.forRoot(), BsDatepickerModule.forRoot(), + TabsModule.forRoot(), CommonModule, FormsModule, + ReactiveFormsModule, SharedModule, RouterModule.forChild(routes) ], diff --git a/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.html b/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.html index 36f7b343d7..67672383b4 100644 --- a/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.html +++ b/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.html @@ -1,23 +1,23 @@
{{bsValue}}
- - - + +

{{bsRangeValue}}
- - - - +
{{ bsRangeValue[0] | date:'yMd'}} - {{ bsRangeValue[1] | date:'yMd'}}
+ + + + diff --git a/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.ts b/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.ts index 334bbf64ec..c5a0c12c35 100644 --- a/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.ts +++ b/demo/src/app/components/+datepicker/demos/bs-popup/date-picker-popup.ts @@ -7,6 +7,24 @@ import { Component } from '@angular/core'; export class DemoDatePickerPopupComponent { minDate = new Date(2017, 5, 10); maxDate = new Date(2018, 9, 15); - bsValue: any ; - bsRangeValue: any = [new Date(2017, 7, 4), new Date(2017, 7, 20)]; + _bsValue: Date; + get bsValue(): Date { + return this._bsValue; + } + + set bsValue(v: Date) { + console.log(v); + this._bsValue = v; + } + + _bsRangeValue: any = [new Date(2017, 7, 4), new Date(2017, 7, 20)]; + get bsRangeValue(): any { + return this._bsRangeValue; + } + + set bsRangeValue(v: any) { + this._bsRangeValue = v; + } + + log(v: any) {console.log(v);} } diff --git a/demo/src/app/components/+datepicker/demos/change-locale/change-locale.html b/demo/src/app/components/+datepicker/demos/change-locale/change-locale.html index cce1fec060..1bb40782c2 100644 --- a/demo/src/app/components/+datepicker/demos/change-locale/change-locale.html +++ b/demo/src/app/components/+datepicker/demos/change-locale/change-locale.html @@ -6,12 +6,13 @@ +
+ +
+ (click)="dp.show()" />
@@ -23,11 +24,11 @@ +
+ +
+ value="Date Range Picker" (click)="dpr.show()"/> diff --git a/demo/src/app/components/+datepicker/demos/color-theming/color-theming.html b/demo/src/app/components/+datepicker/demos/color-theming/color-theming.html index 76c5345de3..0ba705c4dd 100644 --- a/demo/src/app/components/+datepicker/demos/color-theming/color-theming.html +++ b/demo/src/app/components/+datepicker/demos/color-theming/color-theming.html @@ -11,37 +11,17 @@ -
- +
+
+
+ +
+ +
+
+

-
-
- -
-
- -
-
diff --git a/demo/src/app/components/+datepicker/demos/disabled/disabled.component.html b/demo/src/app/components/+datepicker/demos/disabled/disabled.component.html new file mode 100644 index 0000000000..d891b942c6 --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/disabled/disabled.component.html @@ -0,0 +1,13 @@ +
+
+
+ +
+
+
+
+ +
+
+
+ diff --git a/demo/src/app/components/+datepicker/demos/disabled/disabled.component.ts b/demo/src/app/components/+datepicker/demos/disabled/disabled.component.ts new file mode 100644 index 0000000000..8e0a49cff5 --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/disabled/disabled.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'demo-datepicker-disabled', + templateUrl: './disabled.component.html' +}) +export class DemoDatepickerDisabledComponent { + isDisabled = false; +} diff --git a/demo/src/app/components/+datepicker/demos/forms/forms.component.html b/demo/src/app/components/+datepicker/demos/forms/forms.component.html new file mode 100644 index 0000000000..a8cb413c01 --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/forms/forms.component.html @@ -0,0 +1,15 @@ +
+
+ +
+
+ +
+
+
+
+
{{datepickerModel}}
{{daterangepickerModel}}
+
+
+ + diff --git a/demo/src/app/components/+datepicker/demos/forms/forms.component.ts b/demo/src/app/components/+datepicker/demos/forms/forms.component.ts new file mode 100644 index 0000000000..c97900df37 --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/forms/forms.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'demo-datepicker-forms', + templateUrl: './forms.component.html' +}) +export class DemoDatepickerFormsComponent { + datepickerModel: Date; + daterangepickerModel: Date[]; +} diff --git a/demo/src/app/components/+datepicker/demos/index.ts b/demo/src/app/components/+datepicker/demos/index.ts index 8695e4193b..93dc94d1aa 100644 --- a/demo/src/app/components/+datepicker/demos/index.ts +++ b/demo/src/app/components/+datepicker/demos/index.ts @@ -2,12 +2,20 @@ import { DatepickerDemoComponent } from './datepicker-demo.component'; import { DemoDatePickerPopupComponent } from './bs-popup/date-picker-popup'; import { DemoDatepickerColorThemingComponent } from './color-theming/color-theming'; import { DemoDatepickerChangeLocaleComponent } from './change-locale/change-locale'; +import { DemoDatepickerMinMaxComponent } from './min-max/min-max.component'; +import { DemoDatepickerDisabledComponent } from './disabled/disabled.component'; +import { DemoDatepickerFormsComponent } from './forms/forms.component'; +import { DemoDatepickerReactiveFormsComponent } from './reactive-forms/reactive-forms.component'; export const DEMO_COMPONENTS = [ DatepickerDemoComponent, DemoDatePickerPopupComponent, DemoDatepickerColorThemingComponent, - DemoDatepickerChangeLocaleComponent + DemoDatepickerChangeLocaleComponent, + DemoDatepickerMinMaxComponent, + DemoDatepickerDisabledComponent, + DemoDatepickerFormsComponent, + DemoDatepickerReactiveFormsComponent ]; export const DEMOS = { @@ -26,5 +34,21 @@ export const DEMOS = { changeLocale: { component: require('!!raw-loader?lang=typescript!./change-locale/change-locale.ts'), html: require('!!raw-loader?lang=markup!./change-locale/change-locale.html') + }, + minMax: { + component: require('!!raw-loader?lang=typescript!./min-max/min-max.component.ts'), + html: require('!!raw-loader?lang=markup!./min-max/min-max.component.html') + }, + disabled: { + component: require('!!raw-loader?lang=typescript!./disabled/disabled.component.ts'), + html: require('!!raw-loader?lang=markup!./disabled/disabled.component.html') + }, + forms: { + component: require('!!raw-loader?lang=typescript!./forms/forms.component.ts'), + html: require('!!raw-loader?lang=markup!./forms/forms.component.html') + }, + reactive: { + component: require('!!raw-loader?lang=typescript!./reactive-forms/reactive-forms.component.ts'), + html: require('!!raw-loader?lang=markup!./reactive-forms/reactive-forms.component.html') } }; diff --git a/demo/src/app/components/+datepicker/demos/min-max/min-max.component.html b/demo/src/app/components/+datepicker/demos/min-max/min-max.component.html new file mode 100644 index 0000000000..a496be07d5 --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/min-max/min-max.component.html @@ -0,0 +1,14 @@ +
+
+
+ +
+
+
+
+ +
+
+
+ + diff --git a/demo/src/app/components/+datepicker/demos/min-max/min-max.component.ts b/demo/src/app/components/+datepicker/demos/min-max/min-max.component.ts new file mode 100644 index 0000000000..1c8a87747b --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/min-max/min-max.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'demo-datepicker-min-max', + templateUrl: './min-max.component.html' +}) +export class DemoDatepickerMinMaxComponent { + minDate: Date; + maxDate: Date; + + constructor() { + this.minDate = new Date(); + this.maxDate = new Date(); + this.minDate.setDate(this.minDate.getDate() - 1); + this.maxDate.setDate(this.maxDate.getDate() + 7); + } +} diff --git a/demo/src/app/components/+datepicker/demos/reactive-forms/reactive-forms.component.html b/demo/src/app/components/+datepicker/demos/reactive-forms/reactive-forms.component.html new file mode 100644 index 0000000000..57036c2c5d --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/reactive-forms/reactive-forms.component.html @@ -0,0 +1,17 @@ +
+
+
+ +
+
+ +
+
+
+
+
+
{{myForm.value | json}}
+
+
+ + diff --git a/demo/src/app/components/+datepicker/demos/reactive-forms/reactive-forms.component.ts b/demo/src/app/components/+datepicker/demos/reactive-forms/reactive-forms.component.ts new file mode 100644 index 0000000000..74f55d98ad --- /dev/null +++ b/demo/src/app/components/+datepicker/demos/reactive-forms/reactive-forms.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; + +@Component({ + selector: 'demo-datepicker-reactive-forms', + templateUrl: './reactive-forms.component.html' +}) +export class DemoDatepickerReactiveFormsComponent implements OnInit { + myForm: FormGroup; + constructor(private formBuilder: FormBuilder) { } + + ngOnInit() { + this.myForm = this.formBuilder.group({ + date: null, + range: null + }); + } +} diff --git a/demo/src/app/components/+datepicker/docs/title.md b/demo/src/app/components/+datepicker/docs/title.md index e974eacb1d..d7cff8f4ce 100644 --- a/demo/src/app/components/+datepicker/docs/title.md +++ b/demo/src/app/components/+datepicker/docs/title.md @@ -1,11 +1,11 @@ ```typescript // RECOMMENDED (doesn't work with system.js) -import { DatepickerModule } from 'ngx-bootstrap/datepicker'; +import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; // or -import { DatepickerModule } from 'ngx-bootstrap'; +import { BsDatepickerModule } from 'ngx-bootstrap'; @NgModule({ - imports: [DatepickerModule.forRoot(),...] + imports: [BsDatepickerModule.forRoot(),...] }) -export class AppModule(){} +export class AppModule(){} ``` diff --git a/demo/src/app/components/+datepicker/docs/titleOld.md b/demo/src/app/components/+datepicker/docs/titleOld.md new file mode 100644 index 0000000000..e974eacb1d --- /dev/null +++ b/demo/src/app/components/+datepicker/docs/titleOld.md @@ -0,0 +1,11 @@ +```typescript +// RECOMMENDED (doesn't work with system.js) +import { DatepickerModule } from 'ngx-bootstrap/datepicker'; +// or +import { DatepickerModule } from 'ngx-bootstrap'; + +@NgModule({ + imports: [DatepickerModule.forRoot(),...] +}) +export class AppModule(){} +``` diff --git a/demo/src/ng-api-doc.ts b/demo/src/ng-api-doc.ts index 23548dd4e6..4ca408532c 100644 --- a/demo/src/ng-api-doc.ts +++ b/demo/src/ng-api-doc.ts @@ -67,17 +67,17 @@ export const ngdoc: any = { "description": "", "selector": "alert,ngx-alert", "inputs": [ - { - "name": "dismissOnTimeout", - "type": "string | number", - "description": "

Number in milliseconds, after which alert will be closed

\n" - }, { "name": "dismissible", "defaultValue": "false", "type": "boolean", "description": "

If set, displays an inline "Close" button

\n" }, + { + "name": "dismissOnTimeout", + "type": "string | number", + "description": "

Number in milliseconds, after which alert will be closed

\n" + }, { "name": "type", "defaultValue": "warning", @@ -111,18 +111,18 @@ export const ngdoc: any = { "description": "", "methods": [], "properties": [ - { - "name": "dismissOnTimeout", - "defaultValue": "undefined", - "type": "number", - "description": "

default time before alert will dismiss

\n" - }, { "name": "dismissible", "defaultValue": "false", "type": "boolean", "description": "

is alerts are dismissible by default

\n" }, + { + "name": "dismissOnTimeout", + "defaultValue": "undefined", + "type": "number", + "description": "

default time before alert will dismiss

\n" + }, { "name": "type", "defaultValue": "warning", @@ -485,12 +485,15 @@ export const ngdoc: any = { "methods": [], "properties": [] }, - "BsDatepickerConfig": { - "fileName": "src/datepicker/bs-datepicker-config.ts", - "className": "BsDatepickerConfig", + "BsDatepickerInputDirective": { + "fileName": "src/datepicker/bs-datepicker-input.directive.ts", + "className": "BsDatepickerInputDirective", "description": "", - "methods": [], - "properties": [] + "selector": "input[bsDatepicker]", + "inputs": [], + "outputs": [], + "properties": [], + "methods": [] }, "BsDatepickerComponent": { "fileName": "src/datepicker/bs-datepicker.component.ts", @@ -499,33 +502,53 @@ export const ngdoc: any = { "selector": "bs-datepicker,[bsDatepicker]", "exportAs": "bsDatepicker", "inputs": [ + { + "name": "bsConfig", + "type": "Partial", + "description": "

Config object for datepicker

\n" + }, { "name": "bsValue", "type": "Date", - "description": "" + "description": "

Initial value of datepicker

\n" }, { "name": "container", "defaultValue": "body", "type": "string", - "description": "

A selector specifying the element the popover should be appended to.\nCurrently only supports "body".

\n" + "description": "

A selector specifying the element the datepicker should be appended to.\nCurrently only supports "body".

\n" + }, + { + "name": "isDisabled", + "type": "boolean", + "description": "

Indicates whether datepicker is enabled or not

\n" }, { "name": "isOpen", "type": "boolean", - "description": "

Returns whether or not the popover is currently being shown

\n" + "description": "

Returns whether or not the datepicker is currently being shown

\n" + }, + { + "name": "maxDate", + "type": "Date", + "description": "

Maximum date which is available for selection

\n" + }, + { + "name": "minDate", + "type": "Date", + "description": "

Minimum date which is available for selection

\n" }, { "name": "outsideClick", "defaultValue": "true", "type": "boolean", - "description": "" + "description": "

Close datepicker on outside click

\n" }, { "name": "placement", "defaultValue": "bottom", "type": "\"top\" | \"bottom\" | \"left\" | \"right\"", - "description": "

Placement of a popover. Accepts: "top", "bottom", "left", "right"

\n" + "description": "

Placement of a datepicker. Accepts: "top", "bottom", "left", "right"

\n" }, { "name": "triggers", @@ -537,15 +560,15 @@ export const ngdoc: any = { "outputs": [ { "name": "bsValueChange", - "description": "" + "description": "

Emits when datepicker value has been changed

\n" }, { "name": "onHidden", - "description": "

Emits an event when the popover is hidden

\n" + "description": "

Emits an event when the datepicker is hidden

\n" }, { "name": "onShown", - "description": "

Emits an event when the popover is shown

\n" + "description": "

Emits an event when the datepicker is shown

\n" } ], "properties": [], @@ -570,6 +593,13 @@ export const ngdoc: any = { } ] }, + "BsDatepickerConfig": { + "fileName": "src/datepicker/bs-datepicker.config.ts", + "className": "BsDatepickerConfig", + "description": "", + "methods": [], + "properties": [] + }, "BsDaterangepickerComponent": { "fileName": "src/datepicker/bs-daterangepicker.component.ts", "className": "BsDaterangepickerComponent", @@ -577,33 +607,48 @@ export const ngdoc: any = { "selector": "bs-daterangepicker,[bsDaterangepicker]", "exportAs": "bsDaterangepicker", "inputs": [ + { + "name": "bsConfig", + "type": "Partial", + "description": "

Config object for daterangepicker

\n" + }, { "name": "bsValue", "type": "Date[]", - "description": "" + "description": "

Initial value of daterangepicker

\n" }, { "name": "container", "defaultValue": "body", "type": "string", - "description": "

A selector specifying the element the popover should be appended to.\nCurrently only supports "body".

\n" + "description": "

A selector specifying the element the daterangepicker should be appended to.\nCurrently only supports "body".

\n" }, { "name": "isOpen", "type": "boolean", - "description": "

Returns whether or not the popover is currently being shown

\n" + "description": "

Returns whether or not the daterangepicker is currently being shown

\n" + }, + { + "name": "maxDate", + "type": "Date", + "description": "

Maximum date which is available for selection

\n" + }, + { + "name": "minDate", + "type": "Date", + "description": "

Minimum date which is available for selection

\n" }, { "name": "outsideClick", "defaultValue": "true", "type": "boolean", - "description": "" + "description": "

Close daterangepicker on outside click

\n" }, { "name": "placement", "defaultValue": "bottom", "type": "\"top\" | \"bottom\" | \"left\" | \"right\"", - "description": "

Placement of a popover. Accepts: "top", "bottom", "left", "right"

\n" + "description": "

Placement of a daterangepicker. Accepts: "top", "bottom", "left", "right"

\n" }, { "name": "triggers", @@ -615,15 +660,15 @@ export const ngdoc: any = { "outputs": [ { "name": "bsValueChange", - "description": "" + "description": "

Emits when daterangepicker value has been changed

\n" }, { "name": "onHidden", - "description": "

Emits an event when the popover is hidden

\n" + "description": "

Emits an event when the daterangepicker is hidden

\n" }, { "name": "onShown", - "description": "

Emits an event when the popover is shown

\n" + "description": "

Emits an event when the daterangepicker is shown

\n" } ], "properties": [], @@ -709,6 +754,11 @@ export const ngdoc: any = { "type": "Date", "description": "" }, + { + "name": "locale", + "type": "string", + "description": "" + }, { "name": "maxDate", "type": "Date", @@ -931,16 +981,37 @@ export const ngdoc: any = { "properties": [], "methods": [] }, - "FlagMonthViewOptions": { - "fileName": "src/datepicker/engine/flag-month-view.ts", - "className": "FlagMonthViewOptions", + "FlagDaysCalendarOptions": { + "fileName": "src/datepicker/engine/flag-days-calendar.ts", + "className": "FlagDaysCalendarOptions", "description": "", "methods": [], "properties": [] }, - "DaysCalendarModel": { + "FlagMonthCalendarOptions": { + "fileName": "src/datepicker/engine/flag-months-calendar.ts", + "className": "FlagMonthCalendarOptions", + "description": "", + "methods": [], + "properties": [] + }, + "FlagYearsCalendarOptions": { + "fileName": "src/datepicker/engine/flag-years-calendar.ts", + "className": "FlagYearsCalendarOptions", + "description": "", + "methods": [], + "properties": [] + }, + "NavigationViewModel": { "fileName": "src/datepicker/models/index.ts", - "className": "DaysCalendarModel", + "className": "NavigationViewModel", + "description": "
\n", + "methods": [], + "properties": [] + }, + "CalendarCellViewModel": { + "fileName": "src/datepicker/models/index.ts", + "className": "CalendarCellViewModel", "description": "", "methods": [], "properties": [] @@ -948,7 +1019,7 @@ export const ngdoc: any = { "DayViewModel": { "fileName": "src/datepicker/models/index.ts", "className": "DayViewModel", - "description": "", + "description": "
\n", "methods": [], "properties": [] }, @@ -959,24 +1030,45 @@ export const ngdoc: any = { "methods": [], "properties": [] }, - "MonthViewModel": { + "DaysCalendarViewModel": { "fileName": "src/datepicker/models/index.ts", - "className": "MonthViewModel", + "className": "DaysCalendarViewModel", "description": "", "methods": [], "properties": [] }, + "MonthsCalendarViewModel": { + "fileName": "src/datepicker/models/index.ts", + "className": "MonthsCalendarViewModel", + "description": "
\n", + "methods": [], + "properties": [] + }, + "YearsCalendarViewModel": { + "fileName": "src/datepicker/models/index.ts", + "className": "YearsCalendarViewModel", + "description": "
\n", + "methods": [], + "properties": [] + }, + "DaysCalendarModel": { + "fileName": "src/datepicker/models/index.ts", + "className": "DaysCalendarModel", + "description": "
\n
\n", + "methods": [], + "properties": [] + }, "MonthViewOptions": { "fileName": "src/datepicker/models/index.ts", "className": "MonthViewOptions", - "description": "", + "description": "
\n", "methods": [], "properties": [] }, "DatepickerFormatOptions": { "fileName": "src/datepicker/models/index.ts", "className": "DatepickerFormatOptions", - "description": "", + "description": "
\n", "methods": [], "properties": [] }, @@ -994,9 +1086,16 @@ export const ngdoc: any = { "methods": [], "properties": [] }, - "DayHoverEvent": { + "BsViewNavigationEvent": { + "fileName": "src/datepicker/models/index.ts", + "className": "BsViewNavigationEvent", + "description": "", + "methods": [], + "properties": [] + }, + "CellHoverEvent": { "fileName": "src/datepicker/models/index.ts", - "className": "DayHoverEvent", + "className": "CellHoverEvent", "description": "", "methods": [], "properties": [] @@ -1022,6 +1121,47 @@ export const ngdoc: any = { "fileName": "src/datepicker/reducer/bs-datepicker.effects.ts", "className": "BsDatepickerEffects", "description": "", + "methods": [ + { + "name": "setValue", + "description": "

setters

\n", + "args": [ + { + "name": "value", + "type": "Date" + } + ], + "returnType": "void" + }, + { + "name": "setBindings", + "description": "

view to mode bindings

\n", + "args": [ + { + "name": "container", + "type": "BsDatepickerContainer" + } + ], + "returnType": "BsDatepickerEffects" + }, + { + "name": "setEventHandlers", + "description": "

event handlers

\n", + "args": [ + { + "name": "container", + "type": "BsDatepickerContainer" + } + ], + "returnType": "BsDatepickerEffects" + } + ], + "properties": [] + }, + "BsDatepickerViewState": { + "fileName": "src/datepicker/reducer/bs-datepicker.state.ts", + "className": "BsDatepickerViewState", + "description": "", "methods": [], "properties": [] }, @@ -1032,24 +1172,67 @@ export const ngdoc: any = { "methods": [], "properties": [] }, - "BsDatepickerContainerComponent": { - "fileName": "src/datepicker/themes/bs/bs-datepicker-container.component.ts", - "className": "BsDatepickerContainerComponent", + "BsCalendarLayoutComponent": { + "fileName": "src/datepicker/themes/bs/bs-calendar-layout.component.ts", + "className": "BsCalendarLayoutComponent", "description": "", - "selector": "bs-datepicker-container", + "selector": "bs-calendar-layout", + "inputs": [], + "outputs": [], + "properties": [], + "methods": [] + }, + "BsCurrentDateViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-current-date-view.component.ts", + "className": "BsCurrentDateViewComponent", + "description": "", + "selector": "bs-current-date", "inputs": [ { - "name": "value", - "type": "Date", + "name": "title", + "type": "string", "description": "" } ], - "outputs": [ + "outputs": [], + "properties": [], + "methods": [] + }, + "BsCustomDates": { + "fileName": "src/datepicker/themes/bs/bs-custom-dates-view.component.ts", + "className": "BsCustomDates", + "description": "", + "methods": [], + "properties": [] + }, + "BsCustomDatesViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-custom-dates-view.component.ts", + "className": "BsCustomDatesViewComponent", + "description": "", + "selector": "bs-custom-date-view", + "inputs": [ + { + "name": "isCustomRangeShown", + "type": "true", + "description": "" + }, { - "name": "valueChange", + "name": "ranges", + "type": "BsCustomDates[]", "description": "" } ], + "outputs": [], + "properties": [], + "methods": [] + }, + "BsDatepickerContainerComponent": { + "fileName": "src/datepicker/themes/bs/bs-datepicker-container.component.ts", + "className": "BsDatepickerContainerComponent", + "description": "", + "selector": "bs-datepicker-container", + "inputs": [], + "outputs": [], "properties": [], "methods": [] }, @@ -1069,71 +1252,88 @@ export const ngdoc: any = { "properties": [], "methods": [] }, - "BsDatepickerMonthViewComponent": { - "fileName": "src/datepicker/themes/bs/bs-datepicker-month-view.component.ts", - "className": "BsDatepickerMonthViewComponent", + "BsDatepickerNavigationViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-datepicker-navigation-view.component.ts", + "className": "BsDatepickerNavigationViewComponent", "description": "", - "selector": "bs-datepicker-month-view", + "selector": "bs-datepicker-navigation-view", "inputs": [ { - "name": "month", - "type": "MonthViewModel", - "description": "" - }, - { - "name": "options", - "type": "DatepickerRenderOptions", + "name": "calendar", + "type": "DaysCalendarViewModel", "description": "" } ], "outputs": [ { - "name": "onHover", + "name": "onNavigate", "description": "" }, { - "name": "onSelect", + "name": "onViewMode", "description": "" } ], "properties": [], "methods": [] }, - "BsDatepickerNavigationViewComponent": { - "fileName": "src/datepicker/themes/bs/bs-datepicker-navigation-view.component.ts", - "className": "BsDatepickerNavigationViewComponent", + "BsDaterangepickerContainerComponent": { + "fileName": "src/datepicker/themes/bs/bs-daterangepicker-container.component.ts", + "className": "BsDaterangepickerContainerComponent", "description": "", - "selector": "bs-datepicker-navigation-view", + "selector": "bs-daterangepicker-container", + "inputs": [], + "outputs": [], + "properties": [], + "methods": [] + }, + "BsDaysCalendarViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-days-calendar-view.component.ts", + "className": "BsDaysCalendarViewComponent", + "description": "", + "selector": "bs-days-calendar-view", "inputs": [ { - "name": "month", - "type": "MonthViewModel", + "name": "calendar", + "type": "DaysCalendarViewModel", + "description": "" + }, + { + "name": "options", + "type": "DatepickerRenderOptions", "description": "" } ], "outputs": [ + { + "name": "onHover", + "description": "" + }, { "name": "onNavigate", "description": "" + }, + { + "name": "onSelect", + "description": "" + }, + { + "name": "onViewMode", + "description": "" } ], "properties": [], "methods": [] }, - "BsDatepickerViewComponent": { - "fileName": "src/datepicker/themes/bs/bs-datepicker-view.component.ts", - "className": "BsDatepickerViewComponent", + "BsMonthCalendarViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-months-calendar-view.component.ts", + "className": "BsMonthCalendarViewComponent", "description": "", - "selector": "bs-datepicker-view", + "selector": "bs-month-calendar-view", "inputs": [ { - "name": "months", - "type": "MonthViewModel[]", - "description": "" - }, - { - "name": "options", - "type": "DatepickerRenderOptions", + "name": "calendar", + "type": "MonthsCalendarViewModel", "description": "" } ], @@ -1149,32 +1349,65 @@ export const ngdoc: any = { { "name": "onSelect", "description": "" + }, + { + "name": "onViewMode", + "description": "" } ], "properties": [], "methods": [] }, - "BsDaterangepickerContainerComponent": { - "fileName": "src/datepicker/themes/bs/bs-daterangepicker-container.component.ts", - "className": "BsDaterangepickerContainerComponent", + "BsTimepickerViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-timepicker-view.component.ts", + "className": "BsTimepickerViewComponent", "description": "", - "selector": "bs-daterangepicker-container", + "selector": "bs-timepicker", + "inputs": [], + "outputs": [], + "properties": [], + "methods": [] + }, + "BsYearsCalendarViewComponent": { + "fileName": "src/datepicker/themes/bs/bs-years-calendar-view.component.ts", + "className": "BsYearsCalendarViewComponent", + "description": "", + "selector": "bs-years-calendar-view", "inputs": [ { - "name": "value", - "type": "Date[]", + "name": "calendar", + "type": "YearsCalendarViewModel", "description": "" } ], "outputs": [ { - "name": "valueChange", + "name": "onHover", + "description": "" + }, + { + "name": "onNavigate", + "description": "" + }, + { + "name": "onSelect", + "description": "" + }, + { + "name": "onViewMode", "description": "" } ], "properties": [], "methods": [] }, + "MatrixOptions": { + "fileName": "src/datepicker/utils/matrix-utils.ts", + "className": "MatrixOptions", + "description": "", + "methods": [], + "properties": [] + }, "YearPickerComponent": { "fileName": "src/datepicker/yearpicker.component.ts", "className": "YearPickerComponent", @@ -1760,7 +1993,7 @@ export const ngdoc: any = { "name": "placement", "defaultValue": "top", "type": "string", - "description": "

Placement of a popover. Accepts: "top", "bottom", "left", "right"

\n" + "description": "

Placement of a popover. Accepts: "top", "bottom", "left", "right", "auto"

\n" }, { "name": "triggers", @@ -1800,7 +2033,7 @@ export const ngdoc: any = { }, { "name": "placement", - "type": "\"top\" | \"bottom\" | \"left\" | \"right\"", + "type": "\"top\" | \"bottom\" | \"left\" | \"right\" | \"auto\"", "description": "

Placement of a popover. Accepts: "top", "bottom", "left", "right"

\n" }, { diff --git a/src/bs-moment/format.ts b/src/bs-moment/format.ts index 335490c3ba..f8a06b3d23 100644 --- a/src/bs-moment/format.ts +++ b/src/bs-moment/format.ts @@ -26,7 +26,26 @@ export function formatMoment(date: Date, format: string, locale: Locale) { if (!isDateValid(date)) { return locale.invalidDate; } - + format = expandFormat(format, locale); formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); return formatFunctions[format](date, locale); } + +export function expandFormat(format: string, locale: Locale) { + let i = 5; + const localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; + + const replaceLongDateFormatTokens = (input: any) => { + return locale.longDateFormat(input) || input; + }; + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; +} + diff --git a/src/bs-moment/locale/locale.class.ts b/src/bs-moment/locale/locale.class.ts index 149340068d..ba8b13fe20 100644 --- a/src/bs-moment/locale/locale.class.ts +++ b/src/bs-moment/locale/locale.class.ts @@ -16,6 +16,14 @@ export const defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct export const defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); export const defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); export const defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); +export const defaultLongDateFormat: { [index: string]: string } = { + LTS : 'h:mm:ss A', + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY h:mm A', + LLLL : 'dddd, MMMM D, YYYY h:mm A' +}; export interface LocaleData { [key: string]: any; @@ -155,5 +163,22 @@ export class Locale { return this._ordinal.replace('%d', num.toString(10)); } + preparse(str: string) { return str; } + postformat(str: string) { return str; } + + longDateFormat(key: string) { + const format = defaultLongDateFormat[key]; + const formatUpper = defaultLongDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + defaultLongDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, (val: string) => { + return val.slice(1); + }); + + return defaultLongDateFormat[key]; + } } diff --git a/src/datepicker/base/bs-datepicker-container.ts b/src/datepicker/base/bs-datepicker-container.ts index 1c9392a5e0..5ef425ee33 100644 --- a/src/datepicker/base/bs-datepicker-container.ts +++ b/src/datepicker/base/bs-datepicker-container.ts @@ -10,7 +10,7 @@ import { YearsCalendarViewModel } from '../models/index'; -export abstract class BsDatepickerContainer { +export abstract class BsDatepickerAbstractComponent { containerClass: string; _effects: BsDatepickerEffects; @@ -24,6 +24,9 @@ export abstract class BsDatepickerContainer { this._effects.setMaxDate(value); } + set isDisabled(value: boolean) { + this._effects.setDisabled(value); + } viewMode: Observable; daysCalendar: Observable; diff --git a/src/datepicker/bs-datepicker-input.directive.ts b/src/datepicker/bs-datepicker-input.directive.ts new file mode 100644 index 0000000000..1dc55c4fb2 --- /dev/null +++ b/src/datepicker/bs-datepicker-input.directive.ts @@ -0,0 +1,83 @@ +import { Directive, ElementRef, forwardRef, Host, OnInit, Renderer } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { BsDatepickerComponent } from './bs-datepicker.component'; +import { formatDate } from '../bs-moment/format'; +import { BsDatepickerConfig } from './bs-datepicker.config'; +import { getLocale } from '../bs-moment/locale/locales.service'; + +const BS_DATEPICKER_VALUE_ACCESSOR = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => BsDatepickerInputDirective), + multi: true +}; + +@Directive({ + selector: `input[bsDatepicker]`, + host: { + '(change)': 'onChange($event)', + '(keyup.esc)': 'hide()', + '(blur)': 'onBlur()' + }, + providers: [BS_DATEPICKER_VALUE_ACCESSOR] +}) +export class BsDatepickerInputDirective + implements OnInit, ControlValueAccessor { + + private _onChange = Function.prototype; + private _onTouched = Function.prototype; + + constructor(@Host() private _picker: BsDatepickerComponent, + private _config: BsDatepickerConfig, + private _renderer: Renderer, + private _elRef: ElementRef) { + } + + ngOnInit(): void { + this._picker.bsValueChange.subscribe((v: Date) => { + this._renderer.setElementProperty( + this._elRef.nativeElement, + 'value', + formatDate(v, this._picker._config.dateInputFormat, this._picker._config.locale) || '' + ); + this._onChange(v); + }); + } + + onChange(event: any) { + this.writeValue(event.target.value); + this._onTouched(); + } + + writeValue(value: Date | string) { + if (!value) { + this._picker.bsValue = null; + } + const _locale = getLocale(this._picker._config.locale); + if (!_locale) { + throw new Error(`Locale "${this._picker._config.locale}" is not defined, please add it with "defineLocale(...)"`); + } + if (typeof value === 'string') { + const date = new Date(_locale.preparse(value)); + this._picker.bsValue = isNaN(date.valueOf()) ? null : date; + } + + if (value instanceof Date) { + this._picker.bsValue = value; + } + } + + setDisabledState(isDisabled: boolean): void { + this._picker.isDisabled = isDisabled; + this._renderer.setElementAttribute(this._elRef.nativeElement, 'disabled', 'disabled'); + } + + registerOnChange(fn: (value: any) => any): void { this._onChange = fn; } + + registerOnTouched(fn: () => any): void { this._onTouched = fn; } + + onBlur() { this._onTouched(); } + + hide() { + this._picker.hide(); + } +} diff --git a/src/datepicker/bs-datepicker.component.ts b/src/datepicker/bs-datepicker.component.ts index 6afe3fe255..9d15fab658 100644 --- a/src/datepicker/bs-datepicker.component.ts +++ b/src/datepicker/bs-datepicker.component.ts @@ -23,7 +23,7 @@ import { BsDatepickerConfig } from './bs-datepicker.config'; }) export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { /** - * Placement of a popover. Accepts: "top", "bottom", "left", "right" + * Placement of a datepicker. Accepts: "top", "bottom", "left", "right" */ @Input() placement: 'top' | 'bottom' | 'left' | 'right' = 'bottom'; /** @@ -31,16 +31,18 @@ export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { * event names. */ @Input() triggers = 'click'; - + /** + * Close datepicker on outside click + */ @Input() outsideClick = true; /** - * A selector specifying the element the popover should be appended to. + * A selector specifying the element the datepicker should be appended to. * Currently only supports "body". */ @Input() container = 'body'; /** - * Returns whether or not the popover is currently being shown + * Returns whether or not the datepicker is currently being shown */ @Input() public get isOpen(): boolean { @@ -52,18 +54,18 @@ export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { } /** - * Emits an event when the popover is shown + * Emits an event when the datepicker is shown */ @Output() onShown: EventEmitter; /** - * Emits an event when the popover is hidden + * Emits an event when the datepicker is hidden */ @Output() onHidden: EventEmitter; - // @Input() config: BsDatePickerOptions; - // configChange: EventEmitter = new EventEmitter(); - _bsValue: Date; + /** + * Initial value of datepicker + */ @Input() set bsValue(value: Date) { if (this._bsValue === value) { return; } @@ -71,10 +73,25 @@ export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { this.bsValueChange.emit(value); } + /** + * Config object for datepicker + */ @Input() bsConfig: Partial; + /** + * Indicates whether datepicker is enabled or not + */ + @Input() isDisabled: boolean; + /** + * Minimum date which is available for selection + */ @Input() minDate: Date; + /** + * Maximum date which is available for selection + */ @Input() maxDate: Date; - + /** + * Emits when datepicker value has been changed + */ @Output() bsValueChange: EventEmitter = new EventEmitter(); protected _subs: Subscription[] = []; @@ -82,11 +99,12 @@ export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { private _datepicker: ComponentLoader; private _datepickerRef: ComponentRef; - constructor(private _config: BsDatepickerConfig, + constructor(public _config: BsDatepickerConfig, _elementRef: ElementRef, _renderer: Renderer, _viewContainerRef: ViewContainerRef, cis: ComponentLoaderFactory) { + // todo: assign only subset of fields Object.assign(this, this._config); this._datepicker = cis .createLoader(_elementRef, _viewContainerRef, _renderer); @@ -114,6 +132,10 @@ export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { if (changes.maxDate) { this._datepickerRef.instance.maxDate = this.maxDate; } + + if (changes.isDisabled) { + this._datepickerRef.instance.isDisabled = this.isDisabled; + } } /** @@ -125,14 +147,15 @@ export class BsDatepickerComponent implements OnInit, OnDestroy, OnChanges { return; } - const config = Object.assign({}, this._config, this.bsConfig, { + this._config = Object.assign({}, this._config, this.bsConfig, { value: this._bsValue, + isDisabled: this.isDisabled, minDate: this.minDate || this._config.minDate, maxDate: this.maxDate || this._config.maxDate }); this._datepickerRef = this._datepicker - .provide({provide: BsDatepickerConfig, useValue: config}) + .provide({provide: BsDatepickerConfig, useValue: this._config}) .attach(BsDatepickerContainerComponent) .to(this.container) .position({attachment: this.placement}) diff --git a/src/datepicker/bs-datepicker.config.ts b/src/datepicker/bs-datepicker.config.ts index 0f6eea90bb..5c73583fdb 100644 --- a/src/datepicker/bs-datepicker.config.ts +++ b/src/datepicker/bs-datepicker.config.ts @@ -6,6 +6,7 @@ export class BsDatepickerConfig implements DatepickerRenderOptions, DatepickerFormatOptions { value?: Date | Date[]; + isDisabled?: boolean; minDate?: Date; maxDate?: Date; @@ -15,6 +16,11 @@ export class BsDatepickerConfig implements DatepickerRenderOptions, displayMonths = 1; showWeekNumbers = true; + dateInputFormat = 'L'; + // range picker + rangeSeparator = ' - '; + rangeInputFormat = 'L'; + // DatepickerFormatOptions locale = 'en'; monthTitle = 'MMMM'; diff --git a/src/datepicker/bs-datepicker.module.ts b/src/datepicker/bs-datepicker.module.ts index f6cab5ef42..2b6d1b62ab 100644 --- a/src/datepicker/bs-datepicker.module.ts +++ b/src/datepicker/bs-datepicker.module.ts @@ -19,8 +19,22 @@ import { BsCurrentDateViewComponent } from './themes/bs/bs-current-date-view.com import { BsTimepickerViewComponent } from './themes/bs/bs-timepicker-view.component'; import { BsDatepickerConfig } from './bs-datepicker.config'; import { BsCalendarLayoutComponent } from './themes/bs/bs-calendar-layout.component'; +import { BsDatepickerInputDirective } from './bs-datepicker-input.directive'; +import { BsDaterangepickerInputDirective } from './bs-daterangepicker-input.directive'; + import { warnOnce } from '../utils/warn-once'; +const _exports = [ +BsDatepickerContainerComponent, +BsDaterangepickerContainerComponent, + +BsDatepickerComponent, +BsDatepickerInputDirective, + +BsDaterangepickerInputDirective, +BsDaterangepickerComponent +]; + @NgModule({ imports: [CommonModule], declarations: [ @@ -36,15 +50,10 @@ import { warnOnce } from '../utils/warn-once'; BsCustomDatesViewComponent, - BsDatepickerContainerComponent, - BsDaterangepickerContainerComponent, - - BsDatepickerComponent, - BsDaterangepickerComponent + ..._exports ], entryComponents: [BsDatepickerContainerComponent, BsDaterangepickerContainerComponent], - exports: [BsDatepickerContainerComponent, BsDaterangepickerContainerComponent, - BsDatepickerComponent, BsDaterangepickerComponent] + exports: _exports }) export class BsDatepickerModule { constructor() { diff --git a/src/datepicker/bs-datepicker.scss b/src/datepicker/bs-datepicker.scss index f1ed7a1f12..70ee4017bc 100644 --- a/src/datepicker/bs-datepicker.scss +++ b/src/datepicker/bs-datepicker.scss @@ -505,7 +505,7 @@ } /* screen size < 1024px */ -@media (max-width: 1023px) { +@media (max-width: 768px) { bs-datepicker-container, bs-daterangepicker-container { position: fixed !important; diff --git a/src/datepicker/bs-daterangepicker-input.directive.ts b/src/datepicker/bs-daterangepicker-input.directive.ts new file mode 100644 index 0000000000..941014c5e9 --- /dev/null +++ b/src/datepicker/bs-daterangepicker-input.directive.ts @@ -0,0 +1,88 @@ +import { Directive, ElementRef, forwardRef, Host, OnInit, Renderer } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { BsDatepickerConfig } from './bs-datepicker.config'; +import { BsDaterangepickerComponent } from './bs-daterangepicker.component'; +import { formatDate } from '../bs-moment/format'; +import { getLocale } from '../bs-moment/locale/locales.service'; + +const BS_DATERANGEPICKER_VALUE_ACCESSOR = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => BsDaterangepickerInputDirective), + multi: true +}; + +@Directive({ + selector: `input[bsDaterangepicker]`, + host: { + '(change)': 'onChange($event)', + '(keyup.esc)': 'hide()', + '(blur)': 'onBlur()' + }, + providers: [BS_DATERANGEPICKER_VALUE_ACCESSOR] +}) +export class BsDaterangepickerInputDirective + implements OnInit, ControlValueAccessor { + + private _onChange = Function.prototype; + private _onTouched = Function.prototype; + + constructor(@Host() private _picker: BsDaterangepickerComponent, + private _config: BsDatepickerConfig, + private _renderer: Renderer, + private _elRef: ElementRef) { + } + + ngOnInit(): void { + this._picker.bsValueChange.subscribe((v: Date[]) => { + let range = ''; + if (v) { + const start = formatDate(v[0], this._picker._config.rangeInputFormat, this._picker._config.locale); + const end = formatDate(v[1], this._picker._config.rangeInputFormat, this._picker._config.locale); + range = start + this._picker._config.rangeSeparator + end; + } + this._renderer.setElementProperty(this._elRef.nativeElement, 'value', range); + this._onChange(v); + }); + } + + onChange(event: any) { + this.writeValue(event.target.value); + this._onTouched(); + } + + writeValue(value: Date[] | string) { + if (!value) { + this._picker.bsValue = null; + } + + const _locale = getLocale(this._picker._config.locale); + if (!_locale) { + throw new Error(`Locale "${this._picker._config.locale}" is not defined, please add it with "defineLocale(...)"`); + } + if (typeof value === 'string') { + this._picker.bsValue = value + .split(this._picker._config.rangeSeparator) + .map(date => new Date(_locale.preparse(date))) + .map(date => isNaN(date.valueOf()) ? null : date); + } + + if (Array.isArray(value)) { + this._picker.bsValue = value; + } + } + + setDisabledState(isDisabled: boolean): void { + this._picker.isDisabled = isDisabled; + this._renderer.setElementAttribute(this._elRef.nativeElement, 'disabled', 'disabled'); + } + + registerOnChange(fn: (value: any) => any): void { this._onChange = fn; } + + registerOnTouched(fn: () => any): void { this._onTouched = fn; } + + onBlur() { this._onTouched(); } + + hide() { + this._picker.hide(); + } +} diff --git a/src/datepicker/bs-daterangepicker.component.ts b/src/datepicker/bs-daterangepicker.component.ts index b96c6a04ea..0b668d05a6 100644 --- a/src/datepicker/bs-daterangepicker.component.ts +++ b/src/datepicker/bs-daterangepicker.component.ts @@ -16,7 +16,7 @@ import { BsDatepickerConfig } from './bs-datepicker.config'; }) export class BsDaterangepickerComponent implements OnInit, OnDestroy, OnChanges { /** - * Placement of a popover. Accepts: "top", "bottom", "left", "right" + * Placement of a daterangepicker. Accepts: "top", "bottom", "left", "right" */ @Input() placement: 'top' | 'bottom' | 'left' | 'right' = 'bottom'; /** @@ -24,16 +24,18 @@ export class BsDaterangepickerComponent implements OnInit, OnDestroy, OnChanges * event names. */ @Input() triggers = 'click'; - + /** + * Close daterangepicker on outside click + */ @Input() outsideClick = true; /** - * A selector specifying the element the popover should be appended to. + * A selector specifying the element the daterangepicker should be appended to. * Currently only supports "body". */ @Input() container = 'body'; /** - * Returns whether or not the popover is currently being shown + * Returns whether or not the daterangepicker is currently being shown */ @Input() public get isOpen(): boolean { @@ -45,26 +47,43 @@ export class BsDaterangepickerComponent implements OnInit, OnDestroy, OnChanges } /** - * Emits an event when the popover is shown + * Emits an event when the daterangepicker is shown */ @Output() onShown: EventEmitter; /** - * Emits an event when the popover is hidden + * Emits an event when the daterangepicker is hidden */ @Output() onHidden: EventEmitter; _bsValue: Date[]; + /** + * Initial value of daterangepicker + */ @Input() set bsValue(value: Date[]) { if (this._bsValue === value) { return; } this._bsValue = value; this.bsValueChange.emit(value); } - + /** + * Config object for daterangepicker + */ @Input() bsConfig: Partial; + /** + * Indicates whether daterangepicker is enabled or not + */ + @Input() isDisabled: boolean; + /** + * Minimum date which is available for selection + */ @Input() minDate: Date; + /** + * Maximum date which is available for selection + */ @Input() maxDate: Date; - + /** + * Emits when daterangepicker value has been changed + */ @Output() bsValueChange: EventEmitter = new EventEmitter(); protected _subs: Subscription[] = []; @@ -72,7 +91,7 @@ export class BsDaterangepickerComponent implements OnInit, OnDestroy, OnChanges private _datepicker: ComponentLoader; private _datepickerRef: ComponentRef; - constructor(private _config: BsDatepickerConfig, + constructor(public _config: BsDatepickerConfig, _elementRef: ElementRef, _renderer: Renderer, _viewContainerRef: ViewContainerRef, @@ -104,6 +123,10 @@ export class BsDaterangepickerComponent implements OnInit, OnDestroy, OnChanges if (changes.maxDate) { this._datepickerRef.instance.maxDate = this.maxDate; } + + if (changes.isDisabled) { + this._datepickerRef.instance.isDisabled = this.isDisabled; + } } /** @@ -115,18 +138,19 @@ export class BsDaterangepickerComponent implements OnInit, OnDestroy, OnChanges return; } - const config = Object.assign({}, + this._config = Object.assign({}, this._config, {displayMonths: 2}, this.bsConfig, { value: this._bsValue, + isDisabled: this.isDisabled, minDate: this.minDate || this._config.minDate, maxDate: this.maxDate || this._config.maxDate }); this._datepickerRef = this._datepicker - .provide({provide: BsDatepickerConfig, useValue: config}) + .provide({provide: BsDatepickerConfig, useValue: this._config}) .attach(BsDaterangepickerContainerComponent) .to(this.container) .position({attachment: this.placement}) diff --git a/src/datepicker/engine/flag-days-calendar.ts b/src/datepicker/engine/flag-days-calendar.ts index e675fbb8d8..1265005f5c 100644 --- a/src/datepicker/engine/flag-days-calendar.ts +++ b/src/datepicker/engine/flag-days-calendar.ts @@ -1,10 +1,11 @@ -import { DayViewModel, DaysCalendarViewModel, WeekViewModel } from '../models/index'; +import { DaysCalendarViewModel, DayViewModel, WeekViewModel } from '../models/index'; import { isSameDay, isSameMonth } from '../../bs-moment/utils/date-getters'; -import { isSameOrAfter, isSameOrBefore } from '../../bs-moment/utils/date-compare'; +import { isAfter, isBefore } from '../../bs-moment/utils/date-compare'; import { isMonthDisabled } from '../utils/bs-calendar-utils'; import { shiftDate } from '../../bs-moment/utils/date-setters'; export interface FlagDaysCalendarOptions { + isDisabled: boolean; minDate: Date; maxDate: Date; hoveredDate: Date; @@ -38,8 +39,9 @@ export function flagDaysCalendar(formattedMonth: DaysCalendarViewModel, && options.selectedRange && isDateInRange(day.date, options.selectedRange, options.hoveredDate); - const isDisabled = isSameOrBefore(day.date, options.minDate, 'day') - || isSameOrAfter(day.date, options.maxDate, 'day'); + const isDisabled = options.isDisabled + || isBefore(day.date, options.minDate, 'day') + || isAfter(day.date, options.maxDate, 'day'); // decide update or not const newDay = Object.assign({}, day, { @@ -65,10 +67,12 @@ export function flagDaysCalendar(formattedMonth: DaysCalendarViewModel, }); // todo: add check for linked calendars - formattedMonth.hideLeftArrow = options.monthIndex > 0 - && options.monthIndex !== options.displayMonths; - formattedMonth.hideRightArrow = options.monthIndex < options.displayMonths - && (options.monthIndex + 1) !== options.displayMonths; + formattedMonth.hideLeftArrow = options.isDisabled + || (options.monthIndex > 0 + && options.monthIndex !== options.displayMonths); + formattedMonth.hideRightArrow = options.isDisabled + || (options.monthIndex < options.displayMonths + && (options.monthIndex + 1) !== options.displayMonths); formattedMonth.disableLeftArrow = isMonthDisabled( shiftDate(formattedMonth.month, {month: -1}), diff --git a/src/datepicker/engine/flag-months-calendar.ts b/src/datepicker/engine/flag-months-calendar.ts index 02ba2a7e14..4d0cdbbecf 100644 --- a/src/datepicker/engine/flag-months-calendar.ts +++ b/src/datepicker/engine/flag-months-calendar.ts @@ -4,6 +4,7 @@ import { isMonthDisabled, isYearDisabled } from '../utils/bs-calendar-utils'; import { shiftDate } from '../../bs-moment/utils/date-setters'; export interface FlagMonthCalendarOptions { + isDisabled: boolean; minDate: Date; maxDate: Date; hoveredMonth: Date; @@ -17,7 +18,8 @@ export function flagMonthsCalendar(monthCalendar: MonthsCalendarViewModel, .forEach((months: CalendarCellViewModel[], rowIndex: number) => { months.forEach((month: CalendarCellViewModel, monthIndex: number) => { const isHovered = isSameMonth(month.date, options.hoveredMonth); - const isDisabled = isMonthDisabled(month.date, options.minDate, options.maxDate); + const isDisabled = options.isDisabled + || isMonthDisabled(month.date, options.minDate, options.maxDate); const newMonth = Object.assign(/*{},*/ month, {isHovered, isDisabled}); if (month.isHovered !== newMonth.isHovered || month.isDisabled !== newMonth.isDisabled) { diff --git a/src/datepicker/engine/flag-years-calendar.ts b/src/datepicker/engine/flag-years-calendar.ts index bd9dbbb02b..71aecdabaa 100644 --- a/src/datepicker/engine/flag-years-calendar.ts +++ b/src/datepicker/engine/flag-years-calendar.ts @@ -4,6 +4,7 @@ import { isYearDisabled } from '../utils/bs-calendar-utils'; import { shiftDate } from '../../bs-moment/utils/date-setters'; export interface FlagYearsCalendarOptions { + isDisabled: boolean; minDate: Date; maxDate: Date; hoveredYear: Date; @@ -16,7 +17,8 @@ export function flagYearsCalendar(yearsCalendar: YearsCalendarViewModel, options .forEach((years: CalendarCellViewModel[], rowIndex: number) => { years.forEach((year: CalendarCellViewModel, yearIndex: number) => { const isHovered = isSameYear(year.date, options.hoveredYear); - const isDisabled = isYearDisabled(year.date, options.minDate, options.maxDate); + const isDisabled = options.isDisabled + || isYearDisabled(year.date, options.minDate, options.maxDate); const newMonth = Object.assign(/*{},*/ year, {isHovered, isDisabled}); if (year.isHovered !== newMonth.isHovered diff --git a/src/datepicker/reducer/bs-datepicker.actions.ts b/src/datepicker/reducer/bs-datepicker.actions.ts index 1e85b5b01e..4ed32c7bde 100644 --- a/src/datepicker/reducer/bs-datepicker.actions.ts +++ b/src/datepicker/reducer/bs-datepicker.actions.ts @@ -17,6 +17,7 @@ export class BsDatepickerActions { static readonly SET_MIN_DATE = '[datepicker] set min date'; static readonly SET_MAX_DATE = '[datepicker] set max date'; + static readonly SET_IS_DISABLED = '[datepicker] set is disabled'; static readonly SELECT_RANGE = '[daterangepicker] select dates range'; @@ -89,4 +90,11 @@ export class BsDatepickerActions { payload: date }; } + + isDisabled(value: boolean): Action { + return { + type: BsDatepickerActions.SET_IS_DISABLED, + payload: value + }; + } } diff --git a/src/datepicker/reducer/bs-datepicker.effects.ts b/src/datepicker/reducer/bs-datepicker.effects.ts index 1224f0ee06..cab3f18f6e 100644 --- a/src/datepicker/reducer/bs-datepicker.effects.ts +++ b/src/datepicker/reducer/bs-datepicker.effects.ts @@ -3,7 +3,7 @@ import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map'; import { Observable } from 'rxjs/Observable'; import { getFullYear, getMonth } from '../../bs-moment/utils/date-getters'; -import { BsDatepickerContainer } from '../base/bs-datepicker-container'; +import { BsDatepickerAbstractComponent } from '../base/bs-datepicker-container'; import { BsDatepickerConfig } from '../bs-datepicker.config'; import { BsDatepickerViewMode, @@ -63,6 +63,12 @@ export class BsDatepickerEffects { return this; } + setDisabled(value: boolean): BsDatepickerEffects { + this._store.dispatch(this._actions.isDisabled(value)); + + return this; + } + /* Set rendering options */ setOptions(_config: BsDatepickerConfig): BsDatepickerEffects { this._store.dispatch(this._actions.setOptions(_config)); @@ -71,7 +77,7 @@ export class BsDatepickerEffects { } /** view to mode bindings */ - setBindings(container: BsDatepickerContainer): BsDatepickerEffects { + setBindings(container: BsDatepickerAbstractComponent): BsDatepickerEffects { container.daysCalendar = this._store .select(state => state.flaggedMonths) .filter(months => !!months); @@ -96,7 +102,7 @@ export class BsDatepickerEffects { } /** event handlers*/ - setEventHandlers(container: BsDatepickerContainer): BsDatepickerEffects { + setEventHandlers(container: BsDatepickerAbstractComponent): BsDatepickerEffects { container.setViewMode = (event: BsDatepickerViewMode): void => { this._store.dispatch(this._actions.changeViewMode(event)); }; diff --git a/src/datepicker/reducer/bs-datepicker.reducer.ts b/src/datepicker/reducer/bs-datepicker.reducer.ts index 9053c41374..605d86f1ed 100644 --- a/src/datepicker/reducer/bs-datepicker.reducer.ts +++ b/src/datepicker/reducer/bs-datepicker.reducer.ts @@ -123,6 +123,11 @@ export function bsDatepickerReducer(state = initialDatepickerState, action: Acti maxDate: action.payload }); } + case(BsDatepickerActions.SET_IS_DISABLED): { + return Object.assign({}, state, { + isDisabled: action.payload + }); + } default: return state; @@ -215,6 +220,7 @@ function flagReducer(state: BsDatepickerState, action: Action): BsDatepickerStat if (state.view.mode === 'day') { const flaggedMonths = state.formattedMonths .map((formattedMonth, monthIndex) => flagDaysCalendar(formattedMonth, { + isDisabled: state.isDisabled, minDate: state.minDate, maxDate: state.maxDate, hoveredDate: state.hoveredDate, @@ -230,6 +236,7 @@ function flagReducer(state: BsDatepickerState, action: Action): BsDatepickerStat if (state.view.mode === 'month') { const flaggedMonthsCalendar = state.monthsCalendar .map((formattedMonth, monthIndex) => flagMonthsCalendar(formattedMonth, { + isDisabled: state.isDisabled, minDate: state.minDate, maxDate: state.maxDate, hoveredMonth: state.hoveredMonth, @@ -243,6 +250,7 @@ function flagReducer(state: BsDatepickerState, action: Action): BsDatepickerStat if (state.view.mode === 'year') { const yearsCalendarFlagged = state.yearsCalendarModel .map((formattedMonth, yearIndex) => flagYearsCalendar(formattedMonth, { + isDisabled: state.isDisabled, minDate: state.minDate, maxDate: state.maxDate, hoveredYear: state.hoveredYear, diff --git a/src/datepicker/reducer/bs-datepicker.state.ts b/src/datepicker/reducer/bs-datepicker.state.ts index 1e5ceb17a8..bd663c21c6 100644 --- a/src/datepicker/reducer/bs-datepicker.state.ts +++ b/src/datepicker/reducer/bs-datepicker.state.ts @@ -21,6 +21,7 @@ export class BsDatepickerState implements DatepickerRenderOptions, DatepickerFor // initial date of calendar, today by default view: BsDatepickerViewState; + isDisabled?: boolean; // bounds minDate?: Date; maxDate?: Date; diff --git a/src/datepicker/themes/bs/bs-datepicker-container.component.ts b/src/datepicker/themes/bs/bs-datepicker-container.component.ts index 3075c22e03..0687961fea 100644 --- a/src/datepicker/themes/bs/bs-datepicker-container.component.ts +++ b/src/datepicker/themes/bs/bs-datepicker-container.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, OnDestroy, OnInit } from '@angular/core'; -import { BsDatepickerContainer } from '../../base/bs-datepicker-container'; +import { BsDatepickerAbstractComponent } from '../../base/bs-datepicker-container'; import { BsDatepickerConfig } from '../../bs-datepicker.config'; import { DayViewModel } from '../../models/index'; @@ -18,7 +18,7 @@ import { Subscription } from 'rxjs/Subscription'; } }) export class BsDatepickerContainerComponent - extends BsDatepickerContainer + extends BsDatepickerAbstractComponent implements OnInit, OnDestroy { set value(value: Date) { diff --git a/src/datepicker/themes/bs/bs-datepicker-view.html b/src/datepicker/themes/bs/bs-datepicker-view.html index 2548ff5553..b5abf468ca 100644 --- a/src/datepicker/themes/bs/bs-datepicker-view.html +++ b/src/datepicker/themes/bs/bs-datepicker-view.html @@ -22,6 +22,7 @@