|
4 | 4 | // PRE RELEASE
|
5 | 5 | // TODO(jelbourn): make down-arrow a button to open the calendar
|
6 | 6 | // TODO(jelbourn): aria attributes tying together date input and floating calendar.
|
7 |
| - // TODO(jelbourn): actual calendar icon next to input |
8 | 7 | // TODO(jelbourn): something for mobile (probably calendar panel should take up entire screen)
|
9 |
| - // TODO(jelbourn): style to match specification |
10 | 8 | // TODO(jelbourn): make sure this plays well with validation and ngMessages.
|
11 | 9 | // TODO(jelbourn): forward more attributes to the internal input (required, autofocus, etc.)
|
12 | 10 | // TODO(jelbourn): floating panel open animation (see animation for menu in spec).
|
13 | 11 | // TODO(jelbourn): error state
|
| 12 | + // TODO(jelbourn): auto-grow input to accomodate longer dates |
14 | 13 |
|
15 | 14 | // FUTURE VERSION
|
16 | 15 | // TODO(jelbourn): input behavior (masking? auto-complete?)
|
|
30 | 29 | '</md-button>' +
|
31 | 30 | '<div class="md-datepicker-input-container">' +
|
32 | 31 | '<input class="md-datepicker-input">' +
|
33 |
| - '<div class="md-datepicker-expand-triangle" ng-hide="ctrl.isCalendarOpen"></div>' + |
| 32 | + |
| 33 | + '<md-button md-no-ink class="md-datepicker-triangle-button md-icon-button" ' + |
| 34 | + 'ng-click="ctrl.openCalendarPane()">' + |
| 35 | + '<div class="md-datepicker-expand-triangle"></div>' + |
| 36 | + '</md-button>' + |
34 | 37 | '</div>' +
|
35 | 38 |
|
36 | 39 | // This pane (and its shadow) will be detached from here and re-attached to the
|
|
43 | 46 | // inline input / trigger as one shadowed whole.
|
44 | 47 | '<div class="md-date-calendar-pane-shadow md-whiteframe-z1"></div>',
|
45 | 48 | require: ['ngModel', 'mdDatePicker'],
|
46 |
| - scope: {}, |
| 49 | + scope: { |
| 50 | + placeholder: '@mdPlaceholder' |
| 51 | + }, |
47 | 52 | controller: DatePickerCtrl,
|
48 | 53 | controllerAs: 'ctrl',
|
| 54 | + bindToController: true, |
49 | 55 | link: function(scope, element, attr, controllers) {
|
50 | 56 | var ngModelCtrl = controllers[0];
|
51 | 57 | var mdDatePickerCtrl = controllers[1];
|
|
98 | 104 | /** @type {HTMLElement} Shadow for floating calendar pane and input trigger. */
|
99 | 105 | this.calendarShadow = $element[0].querySelector('.md-date-calendar-pane-shadow');
|
100 | 106 |
|
| 107 | + /** @type {HTMLElement} Calendar icon button. */ |
| 108 | + this.calendarButton = $element[0].querySelector('.md-date-picker-button'); |
| 109 | + |
101 | 110 | /** @final {!angular.JQLite} */
|
102 | 111 | this.$element = $element;
|
103 | 112 |
|
|
109 | 118 |
|
110 | 119 | /** @type {boolean} */
|
111 | 120 | this.isDisabled;
|
112 |
| - this.setDisabled($element[0].disabled); |
| 121 | + this.setDisabled($element[0].disabled || angular.isString($attrs['disabled'])); |
113 | 122 |
|
114 | 123 | /** @type {boolean} Whether the date-picker's calendar pane is open. */
|
115 | 124 | this.isCalendarOpen = false;
|
116 | 125 |
|
117 | 126 | /** Pre-bound click handler is saved so that the event listener can be removed. */
|
118 | 127 | this.bodyClickHandler = this.handleBodyClick.bind(this);
|
119 | 128 |
|
120 |
| - // Unless the user specifies so, the calendar should not be a tab stop. |
| 129 | + // Unless the user specifies so, the datepicker should not be a tab stop. |
121 | 130 | // This is necessary because ngAria might add a tabindex to anything with an ng-model
|
122 | 131 | // (based on whether or not the user has turned that particular feature on/off).
|
123 | 132 | if (!$attrs['tabindex']) {
|
|
196 | 205 | });
|
197 | 206 | };
|
198 | 207 |
|
199 |
| - /** Capture properties set to the date-picker and imperitively handle internal changes. */ |
| 208 | + /** |
| 209 | + * Capture properties set to the date-picker and imperitively handle internal changes. |
| 210 | + * This is done to avoid setting up additional $watches. |
| 211 | + */ |
200 | 212 | DatePickerCtrl.prototype.installPropertyInterceptors = function() {
|
201 | 213 | var self = this;
|
202 | 214 |
|
|
206 | 218 | get: function() { return self.isDisabled; },
|
207 | 219 | set: function(value) { self.setDisabled(value) }
|
208 | 220 | });
|
| 221 | + |
| 222 | + Object.defineProperty(this, 'placeholder', { |
| 223 | + get: function() { return self.inputElement.placeholder }, |
| 224 | + set: function(value) { self.inputElement.placeholder = value; } |
| 225 | + }); |
209 | 226 | };
|
210 | 227 |
|
211 | 228 | /**
|
|
220 | 237 | /** Position and attach the floating calendar to the document. */
|
221 | 238 | DatePickerCtrl.prototype.attachCalendarPane = function() {
|
222 | 239 | this.inputContainer.classList.add('md-open');
|
| 240 | + this.calendarButton.classList.add('md-open'); |
| 241 | + |
223 | 242 | var elementRect = this.inputContainer.getBoundingClientRect();
|
224 | 243 |
|
225 | 244 | this.calendarPane.style.left = (elementRect.left + window.pageXOffset) + 'px';
|
|
240 | 259 | /** Detach the floating calendar pane from the document. */
|
241 | 260 | DatePickerCtrl.prototype.detachCalendarPane = function() {
|
242 | 261 | this.inputContainer.classList.remove('md-open');
|
| 262 | + this.calendarButton.classList.remove('md-open'); |
| 263 | + |
243 | 264 | // Use native DOM removal because we do not want any of the angular state of this element
|
244 | 265 | // to be disposed.
|
245 | 266 | this.calendarPane.parentNode.removeChild(this.calendarPane);
|
|
248 | 269 |
|
249 | 270 | /** Open the floating calendar pane. */
|
250 | 271 | DatePickerCtrl.prototype.openCalendarPane = function() {
|
251 |
| - if (!this.isCalendarOpen) { |
| 272 | + if (!this.isCalendarOpen && !this.isDisabled) { |
252 | 273 | this.isCalendarOpen = true;
|
253 | 274 | this.attachCalendarPane();
|
254 | 275 | this.focusCalendar();
|
|
0 commit comments