|
27 | 27 | * @param {(function(Date): boolean)=} md-date-filter Function expecting a date and returning a boolean whether it can be selected or not.
|
28 | 28 | * @param {String=} md-placeholder The date input placeholder value.
|
29 | 29 | * @param {String=} md-open-on-focus When present, the calendar will be opened when the input is focused.
|
| 30 | + * @param {Boolean=} md-is-open Expression that can be used to open the datepicker's calendar on-demand. |
| 31 | + * @param {String=} md-hide-icons Determines which datepicker icons should be hidden. Note that this may cause the |
| 32 | + * datepicker to not align properly with other components. **Use at your own risk.** Possible values are: |
| 33 | + * * `"all"` - Hides all icons. |
| 34 | + * * `"calendar"` - Only hides the calendar icon. |
| 35 | + * * `"triangle"` - Only hides the triangle icon. |
30 | 36 | * @param {boolean=} ng-disabled Whether the datepicker is disabled.
|
31 | 37 | * @param {boolean=} ng-required Whether a value is required for the datepicker.
|
32 | 38 | *
|
|
49 | 55 | */
|
50 | 56 | function datePickerDirective($$mdSvgRegistry) {
|
51 | 57 | return {
|
52 |
| - template: |
53 |
| - // Buttons are not in the tab order because users can open the calendar via keyboard |
54 |
| - // interaction on the text input, and multiple tab stops for one component (picker) |
55 |
| - // may be confusing. |
| 58 | + template: function(tElement, tAttrs) { |
| 59 | + // Buttons are not in the tab order because users can open the calendar via keyboard |
| 60 | + // interaction on the text input, and multiple tab stops for one component (picker) |
| 61 | + // may be confusing. |
| 62 | + var hiddenIcons = tAttrs.mdHideIcons; |
| 63 | + |
| 64 | + var calendarButton = (hiddenIcons === 'all' || hiddenIcons === 'calendar') ? '' : |
56 | 65 | '<md-button class="md-datepicker-button md-icon-button" type="button" ' +
|
57 | 66 | 'tabindex="-1" aria-hidden="true" ' +
|
58 | 67 | 'ng-click="ctrl.openCalendarPane($event)">' +
|
59 | 68 | '<md-icon class="md-datepicker-calendar-icon" aria-label="md-calendar" ' +
|
60 | 69 | 'md-svg-src="' + $$mdSvgRegistry.mdCalendar + '"></md-icon>' +
|
61 |
| - '</md-button>' + |
62 |
| - '<div class="md-datepicker-input-container" ' + |
63 |
| - 'ng-class="{\'md-datepicker-focused\': ctrl.isFocused}">' + |
64 |
| - '<input class="md-datepicker-input" aria-haspopup="true" ' + |
65 |
| - 'ng-focus="ctrl.setFocused(true)" ng-blur="ctrl.setFocused(false)">' + |
66 |
| - '<md-button type="button" md-no-ink ' + |
67 |
| - 'class="md-datepicker-triangle-button md-icon-button" ' + |
68 |
| - 'ng-click="ctrl.openCalendarPane($event)" ' + |
69 |
| - 'aria-label="{{::ctrl.dateLocale.msgOpenCalendar}}">' + |
70 |
| - '<div class="md-datepicker-expand-triangle"></div>' + |
71 |
| - '</md-button>' + |
| 70 | + '</md-button>'; |
| 71 | + |
| 72 | + var triangleButton = (hiddenIcons === 'all' || hiddenIcons === 'triangle') ? '' : |
| 73 | + '<md-button type="button" md-no-ink ' + |
| 74 | + 'class="md-datepicker-triangle-button md-icon-button" ' + |
| 75 | + 'ng-click="ctrl.openCalendarPane($event)" ' + |
| 76 | + 'aria-label="{{::ctrl.dateLocale.msgOpenCalendar}}">' + |
| 77 | + '<div class="md-datepicker-expand-triangle"></div>' + |
| 78 | + '</md-button>'; |
| 79 | + |
| 80 | + return '' + |
| 81 | + calendarButton + |
| 82 | + '<div class="md-datepicker-input-container" ' + |
| 83 | + 'ng-class="{\'md-datepicker-focused\': ctrl.isFocused}">' + |
| 84 | + '<input class="md-datepicker-input" aria-haspopup="true" ' + |
| 85 | + 'ng-focus="ctrl.setFocused(true)" ng-blur="ctrl.setFocused(false)">' + |
| 86 | + triangleButton + |
| 87 | + '</div>' + |
| 88 | + |
| 89 | + // This pane will be detached from here and re-attached to the document body. |
| 90 | + '<div class="md-datepicker-calendar-pane md-whiteframe-z1">' + |
| 91 | + '<div class="md-datepicker-input-mask">' + |
| 92 | + '<div class="md-datepicker-input-mask-opaque"></div>' + |
72 | 93 | '</div>' +
|
73 |
| - |
74 |
| - // This pane will be detached from here and re-attached to the document body. |
75 |
| - '<div class="md-datepicker-calendar-pane md-whiteframe-z1">' + |
76 |
| - '<div class="md-datepicker-input-mask">' + |
77 |
| - '<div class="md-datepicker-input-mask-opaque"></div>' + |
78 |
| - '</div>' + |
79 |
| - '<div class="md-datepicker-calendar">' + |
80 |
| - '<md-calendar role="dialog" aria-label="{{::ctrl.dateLocale.msgCalendar}}" ' + |
81 |
| - 'md-min-date="ctrl.minDate" md-max-date="ctrl.maxDate"' + |
82 |
| - 'md-date-filter="ctrl.dateFilter"' + |
83 |
| - 'ng-model="ctrl.date" ng-if="ctrl.isCalendarOpen">' + |
84 |
| - '</md-calendar>' + |
85 |
| - '</div>' + |
86 |
| - '</div>', |
| 94 | + '<div class="md-datepicker-calendar">' + |
| 95 | + '<md-calendar role="dialog" aria-label="{{::ctrl.dateLocale.msgCalendar}}" ' + |
| 96 | + 'md-min-date="ctrl.minDate" md-max-date="ctrl.maxDate"' + |
| 97 | + 'md-date-filter="ctrl.dateFilter"' + |
| 98 | + 'ng-model="ctrl.date" ng-if="ctrl.isCalendarOpen">' + |
| 99 | + '</md-calendar>' + |
| 100 | + '</div>' + |
| 101 | + '</div>'; |
| 102 | + }, |
87 | 103 | require: ['ngModel', 'mdDatepicker', '?^mdInputContainer'],
|
88 | 104 | scope: {
|
89 | 105 | minDate: '=mdMinDate',
|
90 | 106 | maxDate: '=mdMaxDate',
|
91 | 107 | placeholder: '@mdPlaceholder',
|
92 |
| - dateFilter: '=mdDateFilter' |
| 108 | + dateFilter: '=mdDateFilter', |
| 109 | + isOpen: '=?mdIsOpen' |
93 | 110 | },
|
94 | 111 | controller: DatePickerCtrl,
|
95 | 112 | controllerAs: 'ctrl',
|
|
287 | 304 | this.attachInteractionListeners();
|
288 | 305 |
|
289 | 306 | var self = this;
|
| 307 | + |
290 | 308 | $scope.$on('$destroy', function() {
|
291 | 309 | self.detachCalendarPane();
|
292 | 310 | });
|
| 311 | + |
| 312 | + if ($attrs.mdIsOpen) { |
| 313 | + $scope.$watch('ctrl.isOpen', function(shouldBeOpen) { |
| 314 | + if (shouldBeOpen) { |
| 315 | + self.openCalendarPane({ |
| 316 | + target: self.inputElement |
| 317 | + }); |
| 318 | + } else { |
| 319 | + self.closeCalendarPane(); |
| 320 | + } |
| 321 | + }); |
| 322 | + } |
293 | 323 | }
|
294 | 324 |
|
295 | 325 | /**
|
|
396 | 426 | DatePickerCtrl.prototype.setDisabled = function(isDisabled) {
|
397 | 427 | this.isDisabled = isDisabled;
|
398 | 428 | this.inputElement.disabled = isDisabled;
|
399 |
| - this.calendarButton.disabled = isDisabled; |
| 429 | + |
| 430 | + if (this.calendarButton) { |
| 431 | + this.calendarButton.disabled = isDisabled; |
| 432 | + } |
400 | 433 | };
|
401 | 434 |
|
402 | 435 | /**
|
|
594 | 627 | */
|
595 | 628 | DatePickerCtrl.prototype.openCalendarPane = function(event) {
|
596 | 629 | if (!this.isCalendarOpen && !this.isDisabled) {
|
597 |
| - this.isCalendarOpen = true; |
| 630 | + this.isCalendarOpen = this.isOpen = true; |
598 | 631 | this.calendarPaneOpenedFrom = event.target;
|
599 | 632 |
|
600 | 633 | // Because the calendar pane is attached directly to the body, it is possible that the
|
|
643 | 676 |
|
644 | 677 | function detach() {
|
645 | 678 | self.detachCalendarPane();
|
646 |
| - self.isCalendarOpen = false; |
| 679 | + self.isCalendarOpen = self.isOpen = false; |
647 | 680 | self.ngModelCtrl.$setTouched();
|
648 | 681 |
|
649 | 682 | self.documentElement.off('click touchstart', self.bodyClickHandler);
|
|
0 commit comments