diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts
index 12ab3b830c3b..f24dddf04c3d 100644
--- a/src/lib/datepicker/datepicker-input.ts
+++ b/src/lib/datepicker/datepicker-input.ts
@@ -14,6 +14,7 @@ import {SimpleDate} from '../core/datetime/simple-date';
import {CalendarLocale} from '../core/datetime/calendar-locale';
import {Subscription} from 'rxjs';
import {MdInputContainer} from '../input/input-container';
+import {DOWN_ARROW} from '../core/keyboard/keycodes';
export const MD_DATEPICKER_VALUE_ACCESSOR: any = {
@@ -28,8 +29,12 @@ export const MD_DATEPICKER_VALUE_ACCESSOR: any = {
selector: 'input[mdDatepicker], input[matDatepicker]',
providers: [MD_DATEPICKER_VALUE_ACCESSOR],
host: {
+ '[attr.aria-expanded]': '_datepicker?.opened || "false"',
+ '[attr.aria-haspopup]': 'true',
+ '[attr.aria-owns]': '_datepicker?.id',
'(input)': '_onChange($event.target.value)',
'(blur)': '_onTouched()',
+ '(keydown)': '_onKeydown($event)',
}
})
export class MdDatepickerInput implements AfterContentInit, ControlValueAccessor, OnDestroy {
@@ -40,7 +45,7 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAccessor
this._datepicker._registerInput(this);
}
}
- private _datepicker: MdDatepicker;
+ _datepicker: MdDatepicker;
@Input()
get value(): SimpleDate {
@@ -107,4 +112,11 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAccessor
setDisabledState(disabled: boolean): void {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'disabled', disabled);
}
+
+ _onKeydown(event: KeyboardEvent) {
+ if (event.altKey && event.keyCode === DOWN_ARROW) {
+ this._datepicker.open();
+ event.preventDefault();
+ }
+ }
}
diff --git a/src/lib/datepicker/datepicker-trigger.scss b/src/lib/datepicker/datepicker-trigger.scss
new file mode 100644
index 000000000000..10c049130d78
--- /dev/null
+++ b/src/lib/datepicker/datepicker-trigger.scss
@@ -0,0 +1,11 @@
+$mat-datepicker-trigger-icon-size: 24px !default;
+
+
+.mat-datepicker-trigger {
+ display: inline-block;
+ background: url('data:image/svg+xml;utf8,') no-repeat;
+ background-size: contain;
+ height: $mat-datepicker-trigger-icon-size;
+ width: $mat-datepicker-trigger-icon-size;
+ vertical-align: middle;
+}
diff --git a/src/lib/datepicker/datepicker-trigger.ts b/src/lib/datepicker/datepicker-trigger.ts
new file mode 100644
index 000000000000..473dc07fd3dd
--- /dev/null
+++ b/src/lib/datepicker/datepicker-trigger.ts
@@ -0,0 +1,26 @@
+import {ChangeDetectionStrategy, Component, Input, ViewEncapsulation} from '@angular/core';
+import {MdDatepicker} from './datepicker';
+
+
+@Component({
+ moduleId: module.id,
+ selector: 'md-datepicker-trigger, mat-datepicker-trigger',
+ template: '',
+ styleUrls: ['datepicker-trigger.css'],
+ host: {
+ '[class.mat-datepicker-trigger]': 'true',
+ '(click)': '_open($event)',
+ },
+ encapsulation: ViewEncapsulation.None,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class MdDatepickerTrigger {
+ @Input('for') datepicker: MdDatepicker;
+
+ _open(event: Event): void {
+ if (this.datepicker) {
+ this.datepicker.open();
+ event.stopPropagation();
+ }
+ }
+}
diff --git a/src/lib/datepicker/datepicker.html b/src/lib/datepicker/datepicker.html
index c7cf5a083d31..bf20f86edd3d 100644
--- a/src/lib/datepicker/datepicker.html
+++ b/src/lib/datepicker/datepicker.html
@@ -1,5 +1,6 @@
();
+ opened = false;
+
+ id = `md-datepicker-${datepickerUid++}`;
+
get _selected(): SimpleDate {
return this._datepickerInput ? this._datepickerInput.value : null;
}
@@ -112,6 +119,9 @@ export class MdDatepicker implements OnDestroy {
* @param touchUi Whether to use the touch UI.
*/
open(): void {
+ if (this.opened) {
+ return;
+ }
if (!this._datepickerInput) {
throw new MdError('Attempted to open an MdDatepicker with no associated input.');
}
@@ -121,10 +131,14 @@ export class MdDatepicker implements OnDestroy {
}
this.touchUi ? this._openAsDialog() : this._openAsPopup();
+ this.opened = true;
}
/** Close the calendar. */
close(): void {
+ if (!this.opened) {
+ return;
+ }
if (this._popupRef && this._popupRef.hasAttached()) {
this._popupRef.detach();
}
@@ -135,6 +149,7 @@ export class MdDatepicker implements OnDestroy {
if (this._calendarPortal && this._calendarPortal.isAttached) {
this._calendarPortal.detach();
}
+ this.opened = false;
}
/** Open the calendar as a dialog. */
diff --git a/src/lib/input/input-container.ts b/src/lib/input/input-container.ts
index 8e1c71115be2..eeefcf2155bc 100644
--- a/src/lib/input/input-container.ts
+++ b/src/lib/input/input-container.ts
@@ -291,6 +291,8 @@ export class MdInputContainer implements AfterContentInit {
@ContentChildren(MdHint) _hintChildren: QueryList;
+ @ViewChild('underline') _underlineRef: ElementRef;
+
ngAfterContentInit() {
if (!this._mdInputChild) {
throw new MdInputContainerMissingMdInputError();
@@ -381,4 +383,8 @@ export class MdInputContainer implements AfterContentInit {
this._mdInputChild.ariaDescribedby = ids.join(' ');
}
+
+ getPopupConnectionElementRef(): ElementRef {
+ return this._underlineRef;
+ }
}