|
1 | 1 | (function() {
|
2 | 2 | 'use strict';
|
3 | 3 |
|
4 |
| - // TODO(jelbourn): md-calendar shown in floating panel. |
5 |
| - // TODO(jelbourn): little calendar icon next to input |
6 |
| - // TODO(jelbourn): only one open md-calendar panel at a time per application |
7 |
| - |
8 |
| - |
9 | 4 | angular.module('material.components.calendar')
|
10 | 5 | .directive('mdDatePicker', datePickerDirective);
|
11 | 6 |
|
12 | 7 | function datePickerDirective() {
|
13 | 8 | return {
|
14 | 9 | template:
|
15 |
| - '<input><button type="button" ng-click="ctrl.openCalendarPane()">📅</button>' + |
16 |
| - '<div class="md-date-calendar-pane">' + |
17 |
| - '<md-calendar ng-model="ctrl.date" ng-if="ctrl.isCalendarOpen"></md-calendar>' + |
18 |
| - '</div>', |
19 |
| - // <md-calendar ng-model="ctrl.date"></md-calendar> |
| 10 | + '<div>' + |
| 11 | + '<input ng-model="textValue"> <br>' + |
| 12 | + '<md-calendar ng-model="dateValue"></md-calendar>' + |
| 13 | + '</div>', |
20 | 14 | require: ['ngModel', 'mdDatePicker'],
|
21 | 15 | scope: {},
|
22 | 16 | controller: DatePickerCtrl,
|
23 |
| - controllerAs: 'ctrl', |
24 |
| - link: function(scope, element, attr, controllers) { |
25 |
| - var ngModelCtrl = controllers[0]; |
26 |
| - var mdDatePickerCtrl = controllers[1]; |
27 |
| - |
28 |
| - mdDatePickerCtrl.configureNgModel(ngModelCtrl); |
29 |
| - } |
| 17 | + controllerAs: 'ctrl' |
30 | 18 | };
|
31 | 19 | }
|
32 | 20 |
|
33 |
| - /** |
34 |
| - * Controller for md-date-picker. |
35 |
| - * |
36 |
| - * @ngInject @constructor |
37 |
| - */ |
38 |
| - function DatePickerCtrl($scope, $element, $compile, $timeout, $mdConstant, $mdUtil, |
39 |
| - $$mdDateLocale, $$mdDateUtil) { |
40 |
| - /** @final */ |
41 |
| - this.$compile = $compile; |
42 |
| - |
43 |
| - /** @final */ |
44 |
| - this.$timeout = $timeout; |
45 |
| - |
| 21 | + function DatePickerCtrl($$mdDateLocale) { |
46 | 22 | /** @final */
|
47 | 23 | this.dateLocale = $$mdDateLocale;
|
48 | 24 |
|
49 |
| - /** @final */ |
50 |
| - this.dateUtil = $$mdDateUtil; |
51 |
| - |
52 |
| - /** @final */ |
53 |
| - this.$mdConstant = $mdConstant; |
54 |
| - |
55 |
| - /* @final */ |
56 |
| - this.$mdUtil = $mdUtil; |
57 |
| - |
58 | 25 | /** @type {!angular.NgModelController} */
|
59 | 26 | this.ngModelCtrl = null;
|
60 | 27 |
|
61 |
| - /** @type {HTMLInputElement} */ |
62 |
| - this.inputElement = $element[0].querySelector('input'); |
63 |
| - |
64 |
| - /** @type {HTMLElement} Floating calendar pane (instantiated lazily) */ |
65 |
| - this.calendarPane = $element[0].querySelector('.md-date-calendar-pane'); |
| 28 | + /** @type {string} */ |
| 29 | + this.textValue = ''; |
66 | 30 |
|
67 | 31 | /** @type {Date} */
|
68 |
| - this.date = null; |
69 |
| - |
70 |
| - /** @final {!angular.JQLite} */ |
71 |
| - this.$element = $element; |
72 |
| - |
73 |
| - /** @final {!angular.Scope} */ |
74 |
| - this.$scope = $scope; |
75 |
| - |
76 |
| - /** @type {boolean} Whether the date-picker's calendar pane is open. */ |
77 |
| - this.isCalendarOpen = false; |
78 |
| - |
79 |
| - /** Pre-bound click handler is saved so that the event listener can be removed. */ |
80 |
| - this.bodyClickHandler = this.handleBodyClick.bind(this); |
81 |
| - |
82 |
| - this.attachChangeListeners(); |
83 |
| - this.attachInterationListeners(); |
84 |
| - |
85 |
| - var self = this; |
86 |
| - $scope.$on('$destroy', function() { |
87 |
| - self.detachCalendarPane(); |
88 |
| - }); |
| 32 | + this.dateValue = null; |
89 | 33 | }
|
90 | 34 |
|
91 | 35 | /**
|
|
97 | 41 |
|
98 | 42 | var self = this;
|
99 | 43 | ngModelCtrl.$render = function() {
|
100 |
| - self.date = self.ngModelCtrl.$viewValue; |
101 |
| - self.inputElement.value = self.dateLocale.formatDate(self.date); |
| 44 | + self.dateValue = self.ngModelCtrl.$viewValue |
| 45 | + self.textValue = self.dateLocale.format(self.ngModelCtrl.$viewValue); |
102 | 46 | };
|
103 |
| - }; |
104 |
| - |
105 |
| - /** |
106 |
| - * Attach event listeners for both the text input and the md-calendar. |
107 |
| - * Events are used instead of ng-model so that updates don't infinitely update the other |
108 |
| - * on a change. This should also be more performant than using a $watch. |
109 |
| - */ |
110 |
| - DatePickerCtrl.prototype.attachChangeListeners = function() { |
111 |
| - var self = this; |
112 |
| - |
113 |
| - self.$scope.$on('md-calendar-change', function(event, date) { |
114 |
| - self.ngModelCtrl.$setViewValue(date); |
115 |
| - self.inputElement.value = self.dateLocale.formatDate(date); |
116 |
| - self.closeCalendarPane(); |
117 |
| - }); |
118 |
| - |
119 |
| - // TODO(jelbourn): debounce |
120 |
| - self.inputElement.addEventListener('input', function() { |
121 |
| - var parsedDate = self.dateLocale.parseDate(self.inputElement.value); |
122 |
| - if (self.dateUtil.isValidDate(parsedDate)) { |
123 |
| - self.date = parsedDate; |
124 |
| - self.$scope.$apply(); |
125 |
| - } |
126 |
| - }); |
127 |
| - }; |
128 |
| - |
129 |
| - /** Attach event listeners for user interaction. */ |
130 |
| - DatePickerCtrl.prototype.attachInterationListeners = function() { |
131 |
| - var self = this; |
132 |
| - var $scope = this.$scope; |
133 |
| - var keyCodes = this.$mdConstant.KEY_CODE; |
134 |
| - |
135 |
| - self.inputElement.addEventListener('keydown', function(event) { |
136 |
| - $scope.$apply(function() { |
137 |
| - if (event.altKey && event.keyCode == keyCodes.DOWN_ARROW) { |
138 |
| - self.openCalendarPane(); |
139 |
| - } |
140 |
| - }); |
141 |
| - }); |
142 |
| - |
143 |
| - self.$scope.$on('md-calendar-escape', function() { |
144 |
| - self.closeCalendarPane(); |
145 |
| - }); |
146 |
| - }; |
147 |
| - |
148 |
| - /** Position and attach the floating calendar to the document. */ |
149 |
| - DatePickerCtrl.prototype.attachCalendarPane = function() { |
150 |
| - var elementRect = this.$element[0].getBoundingClientRect(); |
151 |
| - |
152 |
| - this.calendarPane.style.left = elementRect.left + 'px'; |
153 |
| - this.calendarPane.style.top = elementRect.bottom + 'px'; |
154 |
| - document.body.appendChild(this.calendarPane); |
155 |
| - }; |
156 |
| - |
157 |
| - /** Detach the floating calendar pane from the document. */ |
158 |
| - DatePickerCtrl.prototype.detachCalendarPane = function() { |
159 |
| - // Use native DOM removal because we do not want any of the angular state of this element |
160 |
| - // to be disposed. |
161 |
| - this.calendarPane.parentNode.removeChild(this.calendarPane); |
162 |
| - }; |
163 |
| - |
164 |
| - /** Open the floating calendar pane. */ |
165 |
| - DatePickerCtrl.prototype.openCalendarPane = function() { |
166 |
| - if (!this.isCalendarOpen) { |
167 |
| - this.isCalendarOpen = true; |
168 |
| - this.attachCalendarPane(); |
169 |
| - // TODO(jelbourn): dispatch to tell other date pickers to close. |
170 |
| - this.focusCalendar(); |
171 |
| - |
172 |
| - // Attach click listener inside of a timeout because, if this open call was triggered by a |
173 |
| - // click, we don't want it to be immediately propogated up to the body and handled. |
174 |
| - var self = this; |
175 |
| - this.$timeout(function() { |
176 |
| - document.body.addEventListener('click', self.bodyClickHandler); |
177 |
| - }, 0, false); |
178 |
| - } |
179 |
| - }; |
180 |
| - |
181 |
| - /** Close the floating calendar pane. */ |
182 |
| - DatePickerCtrl.prototype.closeCalendarPane = function() { |
183 |
| - this.isCalendarOpen = false; |
184 |
| - this.detachCalendarPane(); |
185 |
| - this.inputElement.focus(); |
186 |
| - document.body.removeEventListener('click', this.bodyClickHandler); |
187 |
| - }; |
188 |
| - |
189 |
| - /** Gets the controller instance for the calendar in the floating pane. */ |
190 |
| - DatePickerCtrl.prototype.getCalendarCtrl = function() { |
191 |
| - return angular.element(this.calendarPane.querySelector('md-calendar')).controller('mdCalendar'); |
192 |
| - }; |
193 |
| - |
194 |
| - /** Focus the calendar in the floating pane. */ |
195 |
| - DatePickerCtrl.prototype.focusCalendar = function() { |
196 |
| - // Use a timeout in order to allow the calendar to be rendered, as it is gated behind an ng-if. |
197 |
| - var self = this; |
198 |
| - this.$timeout(function() { |
199 |
| - self.getCalendarCtrl().focus(); |
200 |
| - }, 0, false); |
201 |
| - }; |
202 |
| - |
203 |
| - /** |
204 |
| - * Handles a click on the document body when the floating calendar pane is open. |
205 |
| - * Closes the floating calendar pane if the click is not inside of it. |
206 |
| - * @param {MouseEvent} event |
207 |
| - */ |
208 |
| - DatePickerCtrl.prototype.handleBodyClick = function(event) { |
209 |
| - if (this.isCalendarOpen) { |
210 |
| - var isInCalendar = this.$mdUtil.getClosest(event.target, 'md-calendar'); |
211 |
| - if (!isInCalendar) { |
212 |
| - this.closeCalendarPane(); |
213 |
| - } |
214 |
| - } |
215 |
| - }; |
| 47 | + } |
216 | 48 | })();
|
0 commit comments