|
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