diff --git a/dist/select.css b/dist/select.css index 0e713bb1b..3b75125a2 100644 --- a/dist/select.css +++ b/dist/select.css @@ -1,7 +1,7 @@ /*! * ui-select * http://github.com/angular-ui/ui-select - * Version: 0.19.7 - 2017-04-15T14:28:36.790Z + * Version: 0.19.8 - 2018-08-29T07:07:49.833Z * License: MIT */ @@ -21,11 +21,10 @@ overflow: hidden !important; position: absolute !important; outline: 0 !important; - left: 0px !important; - top: 0px !important; + left: 0 !important; + top: 0 !important; } - .ui-select-choices-row:hover { background-color: #f5f5f5; } @@ -34,68 +33,84 @@ /* Mark invalid Select2 */ .ng-dirty.ng-invalid > a.select2-choice { - border-color: #D44950; + border-color: #D44950; } .select2-result-single { padding-left: 0; } -.select2-locked > .select2-search-choice-close{ - display:none; +.select2-locked > .select2-search-choice-close { + display: none; } -.select-locked > .ui-select-match-close{ - display:none; +.select-locked > .ui-select-match-close { + display: none; } body > .select2-container.open { z-index: 9999; /* The z-index Select2 applies to the select2-drop */ } +.select2 .ui-select-footer, +.select2 .ui-select-header { + padding: 4px 10px; +} + +.select2 .ui-select-footer { + border-top: 1px solid #dfe5eb; +} + +.select2 .ui-select-header { + border-bottom: 1px solid #dfe5eb; +} + /* Handle up direction Select2 */ .ui-select-container[theme="select2"].direction-up .ui-select-match, .ui-select-container.select2.direction-up .ui-select-match { - border-radius: 4px; /* FIXME hardcoded value :-/ */ - border-top-left-radius: 0; - border-top-right-radius: 0; + border-radius: 4px; /* FIXME hardcoded value :-/ */ + border-top-left-radius: 0; + border-top-right-radius: 0; } + .ui-select-container[theme="select2"].direction-up .ui-select-dropdown, .ui-select-container.select2.direction-up .ui-select-dropdown { - border-radius: 4px; /* FIXME hardcoded value :-/ */ - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + border-radius: 4px; /* FIXME hardcoded value :-/ */ + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; - border-top-width: 1px; /* FIXME hardcoded value :-/ */ - border-top-style: solid; + border-top-width: 1px; /* FIXME hardcoded value :-/ */ + border-top-style: solid; - box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); + box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); - margin-top: -4px; /* FIXME hardcoded value :-/ */ + margin-top: -4px; /* FIXME hardcoded value :-/ */ } + .ui-select-container[theme="select2"].direction-up .ui-select-dropdown .select2-search, .ui-select-container.select2.direction-up .ui-select-dropdown .select2-search { - margin-top: 4px; /* FIXME hardcoded value :-/ */ + margin-top: 4px; /* FIXME hardcoded value :-/ */ } + .ui-select-container[theme="select2"].direction-up.select2-dropdown-open .ui-select-match, .ui-select-container.select2.direction-up.select2-dropdown-open .ui-select-match { - border-bottom-color: #5897fb; + border-bottom-color: #5897fb; } .ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden, -.ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden input{ - opacity: 0; - height: 0; - min-height: 0; - padding: 0; - margin: 0; - border:0; +.ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden input { + opacity: 0; + height: 0; + min-height: 0; + padding: 0; + margin: 0; + border: 0; } /* Selectize theme */ /* Helper class to show styles when focus */ -.selectize-input.selectize-focus{ +.selectize-input.selectize-focus { border-color: #007FBB !important; } @@ -114,25 +129,47 @@ body > .select2-container.open { width: 100%; } +.selectize-dropdown .ui-select-footer, +.selectize-dropdown .ui-select-header { + padding: 5px 8px; +} + +.selectize-dropdown .ui-select-header { + border-bottom: 1px solid #b8b8b8; +} + +.selectize-dropdown .ui-select-footer { + border-top: 1px solid #b8b8b8; +} + /* Mark invalid Selectize */ .ng-dirty.ng-invalid > div.selectize-input { - border-color: #D44950; + border-color: #D44950; } /* Handle up direction Selectize */ .ui-select-container[theme="selectize"].direction-up .ui-select-dropdown { - box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); - margin-top: -2px; /* FIXME hardcoded value :-/ */ + box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); + margin-top: -2px; /* FIXME hardcoded value :-/ */ +} + +.ui-select-container[theme="selectize"] input.ui-select-search-hidden { + opacity: 0; + height: 0; + min-height: 0; + padding: 0; + margin: 0; + border: 0; + width: 0; +} + +.ui-select-container[theme="selectize"] .ui-select-header-group-selectable:hover { + background-color: #f5f5f5; } -.ui-select-container[theme="selectize"] input.ui-select-search-hidden{ - opacity: 0; - height: 0; - min-height: 0; - padding: 0; - margin: 0; - border:0; - width: 0; +.ui-select-container[theme="selectize"] .ui-select-header-group-selectable { + cursor: pointer; + padding-left: 15px; } /* Bootstrap theme */ @@ -166,27 +203,38 @@ body > .select2-container.open { position: static; } +.input-group .ui-select-bootstrap:first-child .form-control { + border-top-left-radius: 4px; /* FIXME hardcoded value :-/ */ + border-bottom-left-radius: 4px; /* FIXME hardcoded value :-/ */ +} + +.input-group .ui-select-bootstrap:last-child .form-control { + border-top-right-radius: 4px; /* FIXME hardcoded value :-/ */ + border-bottom-right-radius: 4px; /* FIXME hardcoded value :-/ */ +} + .input-group > .ui-select-bootstrap > input.ui-select-search.form-control { border-radius: 4px; /* FIXME hardcoded value :-/ */ border-top-right-radius: 0; border-bottom-right-radius: 0; } + .input-group > .ui-select-bootstrap > input.ui-select-search.form-control.direction-up { border-radius: 4px !important; /* FIXME hardcoded value :-/ */ border-top-right-radius: 0 !important; border-bottom-right-radius: 0 !important; } -.ui-select-bootstrap .ui-select-search-hidden{ - opacity: 0; - height: 0; - min-height: 0; - padding: 0; - margin: 0; - border:0; +.ui-select-bootstrap .ui-select-search-hidden { + opacity: 0; + height: 0; + min-height: 0; + padding: 0; + margin: 0; + border: 0; } -.ui-select-bootstrap > .ui-select-match > .btn{ +.ui-select-bootstrap > .ui-select-match > .btn { /* Instead of center because of .btn */ text-align: left !important; } @@ -198,7 +246,8 @@ body > .select2-container.open { } /* See Scrollable Menu with Bootstrap 3 http://stackoverflow.com/questions/19227496 */ -.ui-select-bootstrap > .ui-select-choices ,.ui-select-bootstrap > .ui-select-no-choice { +.ui-select-bootstrap .ui-select-choices, +.ui-select-bootstrap .ui-select-no-choice { width: 100%; height: auto; max-height: 200px; @@ -261,6 +310,22 @@ body > .ui-select-bootstrap.open { border-right: 1px solid #428bca; } + +.ui-select-bootstrap .ui-select-choices { + padding: 5px 0; + margin: 0; + list-style: none; + +.ui-select-bootstrap .ui-select-header-group-selectable:hover { + background-color: #f5f5f5; +} + +.ui-select-bootstrap .ui-select-header-group-selectable { + color: black; + cursor: pointer; + padding: 3px 10px; +} + .ui-select-bootstrap .ui-select-choices-row>span { cursor: pointer; display: block; @@ -272,51 +337,87 @@ body > .ui-select-bootstrap.open { white-space: nowrap; } -.ui-select-bootstrap .ui-select-choices-row>span:hover, .ui-select-bootstrap .ui-select-choices-row>span:focus { - text-decoration: none; - color: #262626; - background-color: #f5f5f5; +.ui-select-bootstrap .ui-select-choices-row > span { + cursor: pointer; + display: block; + padding: 3px 20px; + clear: both; + font-weight: 400; + line-height: 1.42857143; + color: #333; + white-space: nowrap; +} + +.ui-select-bootstrap .ui-select-choices-row > span:hover, .ui-select-bootstrap .ui-select-choices-row > span:focus { + text-decoration: none; + color: #262626; + background-color: #f5f5f5; +} + +.ui-select-bootstrap .ui-select-choices-row.active > span { + color: #fff; + text-decoration: none; + outline: 0; + background-color: #428bca; +} + +.ui-select-bootstrap .ui-select-choices-row.disabled > span, +.ui-select-bootstrap .ui-select-choices-row.active.disabled > span { + color: #777; + cursor: not-allowed; + background-color: #fff; +} + +.ui-select-bootstrap .ui-select-footer, +.ui-select-bootstrap .ui-select-header { + display: block; + padding: 5px 20px; + clear: both; + font-weight: 400; + line-height: 1.42857143; +} + +.ui-select-bootstrap .ui-select-footer { + border-top: 1px solid #dfe5eb; } -.ui-select-bootstrap .ui-select-choices-row.active>span { - color: #fff; - text-decoration: none; - outline: 0; - background-color: #428bca; +.ui-select-bootstrap .ui-select-header { + border-bottom: 1px solid #dfe5eb; } -.ui-select-bootstrap .ui-select-choices-row.disabled>span, -.ui-select-bootstrap .ui-select-choices-row.active.disabled>span { - color: #777; - cursor: not-allowed; - background-color: #fff; +.ui-select-bootstrap .ui-select-dropdown { + width: 100%; + padding: 0; + margin-top: -1px; } /* fix hide/show angular animation */ .ui-select-match.ng-hide-add, .ui-select-search.ng-hide-add { - display: none !important; + display: none !important; } /* Mark invalid Bootstrap */ .ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match { - border-color: #D44950; + border-color: #D44950; } /* Handle up direction Bootstrap */ .ui-select-container[theme="bootstrap"].direction-up .ui-select-dropdown { - box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); + box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); } .ui-select-bootstrap .ui-select-match-text { - width: 100%; - padding-right: 1em; + width: 100%; + padding-right: 1em; } + .ui-select-bootstrap .ui-select-match-text span { - display: inline-block; - width: 100%; - overflow: hidden; + display: inline-block; + width: 100%; + overflow: hidden; } + .ui-select-bootstrap .ui-select-toggle > a.btn { position: absolute; height: 10px; @@ -326,10 +427,10 @@ body > .ui-select-bootstrap.open { /* Spinner */ .ui-select-refreshing.glyphicon { - position: absolute; - right: 0; - padding: 8px 27px; - } + position: absolute; + right: 0; + padding: 8px 27px; +} @-webkit-keyframes ui-select-spin { 0% { @@ -341,6 +442,7 @@ body > .ui-select-bootstrap.open { transform: rotate(359deg); } } + @keyframes ui-select-spin { 0% { -webkit-transform: rotate(0deg); diff --git a/dist/select.js b/dist/select.js index 5ac4e0b70..37cb127a4 100644 --- a/dist/select.js +++ b/dist/select.js @@ -1,7 +1,7 @@ /*! * ui-select * http://github.com/angular-ui/ui-select - * Version: 0.19.7 - 2017-04-15T14:28:36.649Z + * Version: 0.19.8 - 2018-08-29T07:07:49.652Z * License: MIT */ @@ -123,7 +123,8 @@ var uis = angular.module('ui.select', []) appendToBody: false, spinnerEnabled: false, spinnerClass: 'glyphicon glyphicon-refresh ui-select-spin', - backspaceReset: true + backspaceReset: true, + trim: true }) // See Rename minErr and make it accessible from outside https://github.com/angular/angular.js/issues/6913 @@ -184,31 +185,6 @@ var uis = angular.module('ui.select', []) }; }]); -/** - * Debounces functions - * - * Taken from UI Bootstrap $$debounce source code - * See https://github.com/angular-ui/bootstrap/blob/master/src/debounce/debounce.js - * - */ -uis.factory('$$uisDebounce', ['$timeout', function($timeout) { - return function(callback, debounceTime) { - var timeoutPromise; - - return function() { - var self = this; - var args = Array.prototype.slice.call(arguments); - if (timeoutPromise) { - $timeout.cancel(timeoutPromise); - } - - timeoutPromise = $timeout(function() { - callback.apply(self, args); - }, debounceTime); - }; - }; -}]); - uis.directive('uiSelectChoices', ['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', '$window', function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile, $window) { @@ -367,6 +343,11 @@ uis.controller('uiSelectCtrl', return isNil(ctrl.selected) || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0); }; + ctrl.getPlaceholder = function(){ + if(ctrl.selected && ctrl.selected.length) return; + return ctrl.placeholder; + }; + function _findIndex(collection, predicate, thisArg){ if (collection.findIndex){ return collection.findIndex(predicate, thisArg); @@ -390,10 +371,14 @@ uis.controller('uiSelectCtrl', if (ctrl.resetSearchInput) { ctrl.search = EMPTY_SEARCH; //reset activeIndex - if (ctrl.selected && ctrl.items.length && !ctrl.multiple) { - ctrl.activeIndex = _findIndex(ctrl.items, function(item){ - return angular.equals(this, item); - }, ctrl.selected); + if (!ctrl.multiple) { + if (ctrl.selected && ctrl.items.length) { + ctrl.activeIndex = _findIndex(ctrl.items, function(item){ + return angular.equals(this, item); + }, ctrl.selected); + } else { + ctrl.activeIndex = 0; + } } } } @@ -451,7 +436,7 @@ uis.controller('uiSelectCtrl', } else { $timeout(function () { ctrl.focusSearchInput(initSearchValue); - if(!ctrl.tagging.isActivated && ctrl.items.length > 1) { + if(!ctrl.tagging.isActivated && ctrl.items.length > 1 && ctrl.open) { _ensureHighlightVisible(); } }); @@ -468,9 +453,12 @@ uis.controller('uiSelectCtrl', ctrl.searchInput[0].focus(); }; - ctrl.findGroupByName = function(name) { + ctrl.findGroupByName = function(name, noStrict) { return ctrl.groups && ctrl.groups.filter(function(group) { - return group.name === name; + if (noStrict) + return group.name == name; + else + return group.name === name; })[0]; }; @@ -767,11 +755,11 @@ uis.controller('uiSelectCtrl', ctrl.toggle = function(e) { if (ctrl.open) { ctrl.close(); - e.preventDefault(); - e.stopPropagation(); } else { ctrl.activate(); } + e.preventDefault(); + e.stopPropagation(); }; // Set default function for locked choices - avoids unnecessary @@ -874,11 +862,10 @@ uis.controller('uiSelectCtrl', } break; case KEY.UP: - var minActiveIndex = (ctrl.search.length === 0 && ctrl.tagging.isActivated) ? -1 : 0; if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode - else if (ctrl.activeIndex > minActiveIndex) { + else if (ctrl.activeIndex > 0) { var idxmin = --ctrl.activeIndex; - while(_isItemDisabled(ctrl.items[idxmin]) && idxmin > minActiveIndex) { + while(_isItemDisabled(ctrl.items[idxmin]) && idxmin > 0) { ctrl.activeIndex = --idxmin; } } @@ -1058,8 +1045,8 @@ uis.controller('uiSelectCtrl', }]); uis.directive('uiSelect', - ['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout', - function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout) { + ['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout', '$window', + function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout, $window) { return { restrict: 'EA', @@ -1219,6 +1206,10 @@ uis.directive('uiSelect', $select.spinnerClass = spinnerClass !== undefined ? attrs.spinnerClass : uiSelectConfig.spinnerClass; }); + scope.$watch(function () { return scope.$eval(attrs.trim); }, function(newVal) { + $select.trim = newVal !== undefined ? newVal : uiSelectConfig.trim; + }); + //Automatically gets focus when loaded if (angular.isDefined(attrs.autofocus)){ $timeout(function(){ @@ -1265,11 +1256,15 @@ uis.directive('uiSelect', $select.clickTriggeredSelect = false; } - // See Click everywhere but here event http://stackoverflow.com/questions/12931369 - $document.on('click', onDocumentClick); + // See Click everywhere but here. Similar approach to http://stackoverflow.com/questions/12931369 + // but using the capture phase instead of bubble phase of the event propagation. + // + // Using the capture phase avoids problems that araise when event.stopPropatagion() + // is called before the event reaches the `document`. + $window.document.addEventListener('click', onDocumentClick, true); scope.$on('$destroy', function() { - $document.off('click', onDocumentClick); + $window.document.removeEventListener('click', onDocumentClick, true); }); // Move transcluded elements to their correct position in main template @@ -1303,6 +1298,24 @@ uis.directive('uiSelect', if (transcludedNoChoice.length == 1) { element.querySelectorAll('.ui-select-no-choice').replaceWith(transcludedNoChoice); } + + var transcludedHeader = transcluded.querySelectorAll('.ui-select-header'); + transcludedHeader.removeAttr('ui-select-header'); // To avoid loop in case directive as attr + transcludedHeader.removeAttr('data-ui-select-header'); // Properly handle HTML5 data-attributes + if (transcludedHeader.length == 1) { + element.querySelectorAll('.ui-select-header').replaceWith(transcludedHeader); + } else { + element.querySelectorAll('.ui-select-header').remove(); + } + + var transcludedFooter = transcluded.querySelectorAll('.ui-select-footer'); + transcludedFooter.removeAttr('ui-select-footer'); // To avoid loop in case directive as attr + transcludedFooter.removeAttr('data-ui-select-footer'); // Properly handle HTML5 data-attributes + if (transcludedFooter.length == 1) { + element.querySelectorAll('.ui-select-footer').replaceWith(transcludedFooter); + } else { + element.querySelectorAll('.ui-select-footer').remove(); + } }); // Support for appending the select field to the body when its open @@ -1437,7 +1450,7 @@ uis.directive('uiSelect', }; var opened = false; - + scope.calculateDropdownPos = function() { if ($select.open) { dropdown = angular.element(element).querySelectorAll('.ui-select-dropdown'); @@ -1481,6 +1494,117 @@ uis.directive('uiSelect', }; }]); +uis.directive('uiSelectFooter', ['uiSelectConfig', function (uiSelectConfig) { + return { + templateUrl: function (tElement) { + // Needed so the uiSelect can detect the transcluded content + tElement.addClass('ui-select-footer'); + + // Gets theme attribute from parent (ui-select) + var theme = tElement.parent().attr('theme') || uiSelectConfig.theme; + return theme + '/footer.tpl.html'; + }, + restrict: 'EA', + transclude: true, + replace: true + }; +}]); + +uis.directive('uiSelectHeader', ['uiSelectConfig', function (uiSelectConfig) { + return { + templateUrl: function (tElement) { + // Needed so the uiSelect can detect the transcluded content + tElement.addClass('ui-select-header'); + + // Gets theme attribute from parent (ui-select) + var theme = tElement.parent().attr('theme') || uiSelectConfig.theme; + return theme + '/header.tpl.html'; + }, + restrict: 'EA', + transclude: true, + replace: true + }; +}]); + +uis.directive('uiSelectHeaderGroupSelectable', ['$timeout', function($timeout) { + return { + restrict: 'EA', + require: ['^uiSelect'], + scope: { + isEnabled: " 0\">