From c66a26285940f4d596990edf12896b9230f41701 Mon Sep 17 00:00:00 2001 From: Stefan Zollinger Date: Tue, 22 Aug 2017 15:10:56 +0200 Subject: [PATCH] fix(uiSelectCtrl): properly calculate container width - Account for paddings on input container in case box-sizing: border-box is set. - Added some tests for this case Closes #1980. --- src/common.js | 20 ++++++++++++++ src/uiSelectController.js | 9 +++---- test/select.spec.js | 56 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/common.js b/src/common.js index 89848e57c..1d249e005 100644 --- a/src/common.js +++ b/src/common.js @@ -172,4 +172,24 @@ var uis = angular.module('ui.select', []) left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft) }; }; +}]) + +/** + * Gets an elements inner width (width minus padding) + */ +.factory('uisElementInnerWidth', + ['$window', + function ($window) { + return $window.jQuery ? getInnerWidthJQuery : getInnerWidth; + + function getInnerWidthJQuery(element) { + return element.width(); + } + + function getInnerWidth(element) { + var style = $window.getComputedStyle(element[0]); + var paddingLeft = parseFloat(style.getPropertyValue('padding-left')); + var paddingRight = parseFloat(style.getPropertyValue('padding-right')); + return element[0].clientWidth - paddingLeft - paddingRight; + } }]); diff --git a/src/uiSelectController.js b/src/uiSelectController.js index a92b94d2a..2191329e3 100644 --- a/src/uiSelectController.js +++ b/src/uiSelectController.js @@ -5,8 +5,8 @@ * put as much logic in the controller (instead of the link functions) as possible so it can be easily tested. */ uis.controller('uiSelectCtrl', - ['$scope', '$element', '$timeout', '$filter', '$$uisDebounce', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window', - function($scope, $element, $timeout, $filter, $$uisDebounce, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window) { + ['$scope', '$element', '$timeout', '$filter', '$$uisDebounce', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window', 'uisElementInnerWidth', + function($scope, $element, $timeout, $filter, $$uisDebounce, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window, uisElementInnerWidth) { var ctrl = this; @@ -534,10 +534,9 @@ uis.controller('uiSelectCtrl', ctrl.sizeSearchInput = function() { var input = ctrl.searchInput[0], - container = ctrl.$element[0], calculateContainerWidth = function() { // Return the container width only if the search input is visible - return container.clientWidth * !!input.offsetParent; + return uisElementInnerWidth(ctrl.$element) * !!input.offsetParent; }, updateIfVisible = function(containerWidth) { if (containerWidth === 0) { @@ -549,7 +548,7 @@ uis.controller('uiSelectCtrl', return true; }; - ctrl.searchInput.css('width', '10px'); + ctrl.searchInput.css('width', '50px'); $timeout(function() { //Give tags time to render correctly if (sizeWatch === null && !updateIfVisible(calculateContainerWidth())) { sizeWatch = $scope.$watch(function() { diff --git a/test/select.spec.js b/test/select.spec.js index 7f6f6a98f..73859c3ac 100644 --- a/test/select.spec.js +++ b/test/select.spec.js @@ -2060,6 +2060,62 @@ describe('ui-select tests', function () { }); + it('input size should properly account for container paddings if box-sizing is set to border-box', function () { + var el = createUiSelectMultiple({ + tagging: '', + taggingLabel: 'false' + }); + + angular.element(document.body).append(el); + // Set fixed match item width for easier testing + var style = $( + '' + ); + + $('head').append(style); + + var searchInput = el.find('.ui-select-search'); + + el.css({ + paddingLeft: '6px', + paddingRight: '6px' + }); + + $timeout.flush(); + + var fullWidth = searchInput.outerWidth(); + var matchItemWidth = 260; + + expect(searchInput.outerWidth()).toBe(el.width() - 6); // Full width minus padding due to nested div + + clickItem(el, 'Wladimir'); + $timeout.flush(); + // 1 items selected, input should be less than full width minus the invisible text node and one item with + expect(searchInput.outerWidth()).toBe(fullWidth - matchItemWidth ); // remaining width of the row + + clickItem(el, 'Samantha'); + $timeout.flush(); + // Input should be smaller than before + expect(searchInput.outerWidth()).toBe(fullWidth - (2 * matchItemWidth)); + + clickItem(el, 'Adrian'); + $timeout.flush(); + // Minimum input width is 50px, we should be on a new line now + expect(searchInput.outerWidth()).toBe(fullWidth); + + el.remove(); + style.remove(); + }); + it('should update size of search input use container width', function () { scope.selection.selectedMultiple = [scope.people[4], scope.people[5]]; //Wladimir & Samantha var el = createUiSelectMultiple({