Skip to content

Commit 0dab2b5

Browse files
committed
feat(datepicker): migrate to mdPanel
Migrates the datepicker's positioning logic to mdPanel. All the functionality should work as before. Fixes angular#9564.
1 parent c5b5386 commit 0dab2b5

File tree

6 files changed

+273
-414
lines changed

6 files changed

+273
-414
lines changed

src/components/datepicker/datePicker.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
angular.module('material.components.datepicker', [
88
'material.core',
99
'material.components.icon',
10-
'material.components.virtualRepeat'
10+
'material.components.virtualRepeat',
11+
'material.components.panel'
1112
]);

src/components/datepicker/datePicker.scss

+2-17
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,8 @@ md-datepicker {
116116
}
117117
}
118118

119-
.md-datepicker-is-showing .md-scroll-mask {
120-
z-index: $z-index-calendar-pane - 1;
121-
}
122-
123119
// Floating pane that contains the calendar at the bottom of the input.
124120
.md-datepicker-calendar-pane {
125-
// On most browsers the `scale(0)` below prevents this element from
126-
// overflowing it's parent, however IE and Edge seem to disregard it.
127-
// The `left: -100%` pulls the element back in order to ensure that
128-
// it doesn't cause an overflow.
129-
position: absolute;
130-
top: 0;
131-
left: -100%;
132121
z-index: $z-index-calendar-pane;
133122
border-width: 1px;
134123
border-style: solid;
@@ -149,19 +138,15 @@ md-datepicker {
149138
width: $md-calendar-width;
150139
position: relative;
151140
overflow: hidden;
152-
153-
background: transparent;
154-
pointer-events: none;
155-
cursor: text;
156141
}
157142

158143
// The calendar portion of the floating pane (vs. the input mask).
159144
.md-datepicker-calendar {
160-
opacity: 0;
161145
// Use a modified timing function (from swift-ease-out) so that the opacity part of the
162146
// animation doesn't come in as quickly so that the floating pane doesn't ever seem to
163147
// cover up the trigger input.
164148
transition: opacity $md-datepicker-open-animation-duration cubic-bezier(0.5, 0, 0.25, 1);
149+
opacity: 0;
165150

166151
.md-pane-open & {
167152
opacity: 1;
@@ -194,7 +179,7 @@ md-datepicker {
194179
.md-datepicker-triangle-button {
195180
position: absolute;
196181
@include rtl-prop(right, left, 0, auto);
197-
top: $md-date-arrow-size;
182+
top: $md-date-arrow-size / 2;
198183

199184
// TODO(jelbourn): This position isn't great on all platforms.
200185
@include rtl(transform, translateY(-25%) translateX(45%), translateY(-25%) translateX(-45%));

src/components/datepicker/js/calendar.js

+31-25
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@
5858
minDate: '=mdMinDate',
5959
maxDate: '=mdMaxDate',
6060
dateFilter: '=mdDateFilter',
61-
_currentView: '@mdCurrentView'
61+
_currentView: '@mdCurrentView',
62+
63+
// private way of passing in the panel from the datepicker
64+
_panelRef: '=mdPanelRef'
6265
},
6366
require: ['ngModel', 'mdCalendar'],
6467
controller: CalendarCtrl,
@@ -197,13 +200,18 @@
197200

198201
var boundKeyHandler = angular.bind(this, this.handleKeyEvent);
199202

200-
// Bind the keydown handler to the body, in order to handle cases where the focused
201-
// element gets removed from the DOM and stops propagating click events.
202-
angular.element(document.body).on('keydown', boundKeyHandler);
203+
if (this._panelRef) {
204+
// Bind the keydown handler to the body, in order to handle cases where the focused
205+
// element gets removed from the DOM and stops propagating key events.
206+
angular.element(document.body).on('keydown', boundKeyHandler);
203207

204-
$scope.$on('$destroy', function() {
205-
angular.element(document.body).off('keydown', boundKeyHandler);
206-
});
208+
$scope.$on('$destroy', function() {
209+
angular.element(document.body).off('keydown', boundKeyHandler);
210+
});
211+
} else {
212+
// If the calendar on it's own, it shouldn't bind global key handlers.
213+
$element.on('keydown', boundKeyHandler);
214+
}
207215

208216
if (this.minDate && this.minDate > $mdDateLocale.firstRenderableDate) {
209217
this.firstRenderableDate = this.minDate;
@@ -345,27 +353,25 @@
345353
CalendarCtrl.prototype.handleKeyEvent = function(event) {
346354
var self = this;
347355

348-
this.$scope.$apply(function() {
349-
// Capture escape and emit back up so that a wrapping component
350-
// (such as a date-picker) can decide to close.
351-
if (event.which == self.keyCode.ESCAPE || event.which == self.keyCode.TAB) {
352-
self.$scope.$emit('md-calendar-close');
353-
354-
if (event.which == self.keyCode.TAB) {
356+
if (!this._panelRef || this._panelRef.isAttached) {
357+
this.$scope.$apply(function() {
358+
// Capture tabbing and emit back up so that a wrapping component
359+
// (such as a date-picker) can decide to close.
360+
if (event.which === self.keyCode.TAB) {
361+
self.$scope.$emit('md-calendar-close');
355362
event.preventDefault();
363+
return;
356364
}
357365

358-
return;
359-
}
360-
361-
// Broadcast the action that any child controllers should take.
362-
var action = self.getActionFromKeyEvent(event);
363-
if (action) {
364-
event.preventDefault();
365-
event.stopPropagation();
366-
self.$scope.$broadcast('md-calendar-parent-action', action);
367-
}
368-
});
366+
// Broadcast the action that any child controllers should take.
367+
var action = self.getActionFromKeyEvent(event);
368+
if (action) {
369+
event.preventDefault();
370+
event.stopPropagation();
371+
self.$scope.$broadcast('md-calendar-parent-action', action);
372+
}
373+
});
374+
}
369375
};
370376

371377
/**

src/components/datepicker/js/calendar.spec.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ describe('md-calendar', function() {
113113
function dispatchKeyEvent(keyCode, opt_modifiers) {
114114
var mod = opt_modifiers || {};
115115

116-
angular.element(document.body).triggerHandler({
116+
calendarController.$element.triggerHandler({
117117
type: 'keydown',
118118
keyCode: keyCode,
119119
which: keyCode,
@@ -665,19 +665,19 @@ describe('md-calendar', function() {
665665
});
666666
});
667667

668-
it('should fire an event when escape is pressed', function() {
669-
var escapeHandler = jasmine.createSpy('escapeHandler');
670-
pageScope.$on('md-calendar-close', escapeHandler);
668+
it('should fire an event when tabbing away', function() {
669+
var tabHandler = jasmine.createSpy('tabHandler');
670+
pageScope.$on('md-calendar-close', tabHandler);
671671

672672
pageScope.myDate = new Date(2014, FEB, 11);
673673
applyDateChange();
674674
var selectedDate = element.querySelector('.md-calendar-selected-date');
675675
selectedDate.focus();
676676

677-
dispatchKeyEvent(keyCodes.ESCAPE);
677+
dispatchKeyEvent(keyCodes.TAB);
678678
pageScope.$apply();
679679

680-
expect(escapeHandler).toHaveBeenCalled();
680+
expect(tabHandler).toHaveBeenCalled();
681681
});
682682
});
683683

0 commit comments

Comments
 (0)