Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

feat(datepicker): implement auto position #5444

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/datepicker/datepicker.css
Original file line number Diff line number Diff line change
@@ -8,6 +8,11 @@

.uib-datepicker-popup.dropdown-menu {
display: block;
float: none;
visibility: hidden;
margin: 0;
top: -9999px;
left: -9999px;
}

.uib-button-bar {
49 changes: 42 additions & 7 deletions src/datepicker/datepicker.js
Original file line number Diff line number Diff line change
@@ -332,6 +332,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
} else {
self.activeDate = date;
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
$scope.$emit('uib:datepicker.mode');
}
};

@@ -351,6 +352,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
}

$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
$scope.$emit('uib:datepicker.mode');
};

// Key event mapper
@@ -717,15 +719,16 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
'month': 'yyyy-MM'
},
onOpenFocus: true,
showButtonBar: true
showButtonBar: true,
placement: 'auto bottom-left'
})

.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', 'uibDatepickerPopupAttributeWarning',
function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, datepickerPopupAttributeWarning) {
.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$window', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', 'uibDatepickerPopupAttributeWarning',
function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, datepickerPopupAttributeWarning) {
var cache = {},
isHtml5DateInput = false;
var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl, scrollParentEl,
ngModel, ngModelOptions, $popup, altInputFormats, watchListeners = [];

$scope.watchData = {};
@@ -965,6 +968,10 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
$popup.remove();
$element.off('keydown', inputKeydownBind);
$document.off('click', documentClickBind);
if (scrollParentEl) {
scrollParentEl.off('scroll', positionPopup);
}
angular.element($window).off('resize', positionPopup);

//Clear all watch listeners on destroy
while (watchListeners.length) {
@@ -1045,20 +1052,35 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
$scope.$watch('isOpen', function(value) {
if (value) {
if (!$scope.disabled) {
$scope.position = appendToBody ? $position.offset($element) : $position.position($element);
$scope.position.top = $scope.position.top + $element.prop('offsetHeight');

$timeout(function() {
positionPopup();

if (onOpenFocus) {
$scope.$broadcast('uib:datepicker.focus');
}
$document.on('click', documentClickBind);

var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
if (appendToBody || $position.parsePlacement(placement)[2]) {
scrollParentEl = scrollParentEl || angular.element($position.scrollParent($element));
if (scrollParentEl) {
scrollParentEl.on('scroll', positionPopup);
}
} else {
scrollParentEl = null;
}

angular.element($window).on('resize', positionPopup);
}, 0, false);
} else {
$scope.isOpen = false;
}
} else {
$document.off('click', documentClickBind);
if (scrollParentEl) {
scrollParentEl.off('scroll', positionPopup);
}
angular.element($window).off('resize', positionPopup);
}
});

@@ -1162,6 +1184,19 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
});
}
}

function positionPopup() {
if ($scope.isOpen) {
var dpElement = $popup[0].querySelector('.uib-datepicker-popup');
var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
var position = $position.positionElements($element, dpElement, placement, appendToBody);
angular.element(dpElement).css({top: position.top + 'px', left: position.left + 'px', visibility: 'visible'});
}
}

$scope.$on('uib:datepicker.mode', function() {
$timeout(positionPopup, 0, false);
});
}])

.directive('uibDatepickerPopup', function() {
22 changes: 20 additions & 2 deletions src/datepicker/docs/readme.md
Original file line number Diff line number Diff line change
@@ -78,7 +78,7 @@ The datepicker has 3 modes:
* `format-month-title`
<small class="badge">C</small>
_(Default: `yyyy`)_ -
Format of title when selecting month.
Format of title when selecting month.

* `init-date`
<small class="badge">$</small>
@@ -210,7 +210,7 @@ The popup is a wrapper that you can use in an input to toggle a datepicker. To c
* `datepicker-template-url`
<small class="badge">C</small>
_(Default: `uib/template/datepicker/datepicker.html`)_ -
Add the ability to override the template used on the component (inner uib-datepicker).
Add the ability to override the template used on the component (inner uib-datepicker).

* `is-open`
<small class="badge">$</small>
@@ -235,6 +235,24 @@ The popup is a wrapper that you can use in an input to toggle a datepicker. To c
_(Default: `text`, Config: `html5Types`)_ -
You can override the input type to be _(date|datetime-local|month)_. That will change the date format of the popup.

* `popup-placement`
<small class="badge">C</small>
_(Default: `auto bottom-left`, Config: 'placement')_ -
Passing in 'auto' separated by a space before the placement will enable auto positioning, e.g: "auto bottom-left". The popup will attempt to position where it fits in the closest scrollable ancestor. Accepts:

* `top` - popup on top, horizontally centered on input element.
* `top-left` - popup on top, left edge aligned with input element left edge.
* `top-right` - popup on top, right edge aligned with input element right edge.
* `bottom` - popup on bottom, horizontally centered on input element.
* `bottom-left` - popup on bottom, left edge aligned with input element left edge.
* `bottom-right` - popup on bottom, right edge aligned with input element right edge.
* `left` - popup on left, vertically centered on input element.
* `left-top` - popup on left, top edge aligned with input element top edge.
* `left-bottom` - popup on left, bottom edge aligned with input element bottom edge.
* `right` - popup on right, vertically centered on input element.
* `right-top` - popup on right, top edge aligned with input element top edge.
* `right-bottom` - popup on right, bottom edge aligned with input element bottom edge.

* `uib-datepicker-popup`
<small class="badge">C</small>
_(Default: `yyyy-MM-dd`, Config: `datepickerConfig`)_ -