11/*!
22 * ui-select
33 * http://github.com/angular-ui/ui-select
4- * Version: 0.14.8 - 2016-02-18T22:01:43.792Z
4+ * Version: 0.15.0 - 2016-03-15T17:20:10.014Z
55 * License: MIT
66 */
77
@@ -109,6 +109,7 @@ var uis = angular.module('ui.select', [])
109109 placeholder : '' , // Empty by default, like HTML tag <select>
110110 refreshDelay : 1000 , // In milliseconds
111111 closeOnSelect : true ,
112+ skipFocusser : false ,
112113 dropdownPosition : 'auto' ,
113114 generateId : function ( ) {
114115 return latestId ++ ;
@@ -224,15 +225,15 @@ uis.directive('uiSelectChoices',
224225 . attr ( 'ng-if' , '$select.open' ) ; //Prevent unnecessary watches when dropdown is closed
225226 if ( $window . document . addEventListener ) { //crude way to exclude IE8, specifically, which also cannot capture events
226227 choices . attr ( 'ng-mouseenter' , '$select.setActiveItem(' + $select . parserResult . itemName + ')' )
227- . attr ( 'ng-click' , '$select.select(' + $select . parserResult . itemName + ',false ,$event)' ) ;
228+ . attr ( 'ng-click' , '$select.select(' + $select . parserResult . itemName + ',$select.skipFocusser ,$event)' ) ;
228229 }
229230
230231 var rowsInner = element . querySelectorAll ( '.ui-select-choices-row-inner' ) ;
231232 if ( rowsInner . length !== 1 ) throw uiSelectMinErr ( 'rows' , "Expected 1 .ui-select-choices-row-inner but got '{0}'." , rowsInner . length ) ;
232233 rowsInner . attr ( 'uis-transclude-append' , '' ) ; //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
233234 if ( ! $window . document . addEventListener ) { //crude way to target IE8, specifically, which also cannot capture events - so event bindings must be here
234235 rowsInner . attr ( 'ng-mouseenter' , '$select.setActiveItem(' + $select . parserResult . itemName + ')' )
235- . attr ( 'ng-click' , '$select.select(' + $select . parserResult . itemName + ',false ,$event)' ) ;
236+ . attr ( 'ng-click' , '$select.select(' + $select . parserResult . itemName + ',$select.skipFocusser ,$event)' ) ;
236237 }
237238
238239 $compile ( element , transcludeFn ) ( scope ) ; //Passing current transcludeFn to be able to append elements correctly from uisTranscludeAppend
@@ -279,6 +280,7 @@ uis.controller('uiSelectCtrl',
279280
280281 ctrl . removeSelected = false ; //If selected item(s) should be removed from dropdown list
281282 ctrl . closeOnSelect = true ; //Initialized inside uiSelect directive link function
283+ ctrl . skipFocusser = false ; //Set to true to avoid returning focus to ctrl when item is selected
282284 ctrl . search = EMPTY_SEARCH ;
283285
284286 ctrl . activeIndex = 0 ; //Dropdown of choices
@@ -381,7 +383,7 @@ uis.controller('uiSelectCtrl',
381383 }
382384
383385 var container = $element . querySelectorAll ( '.ui-select-choices-content' ) ;
384- if ( ctrl . $animate && ctrl . $animate . enabled ( container [ 0 ] ) ) {
386+ if ( ctrl . $animate && ctrl . $animate . on && ctrl . $animate . enabled ( container [ 0 ] ) ) {
385387 ctrl . $animate . on ( 'enter' , container [ 0 ] , function ( elem , phase ) {
386388 if ( phase === 'close' ) {
387389 // Only focus input after the animation has finished
@@ -482,7 +484,11 @@ uis.controller('uiSelectCtrl',
482484 ctrl . setItemsFn ( data ) ;
483485 } else {
484486 if ( data !== undefined ) {
485- var filteredItems = data . filter ( function ( i ) { return selectedItems && selectedItems . indexOf ( i ) < 0 ; } ) ;
487+ var filteredItems = data . filter ( function ( i ) {
488+ return selectedItems . every ( function ( selectedItem ) {
489+ return ! angular . equals ( i , selectedItem ) ;
490+ } ) ;
491+ } ) ;
486492 ctrl . setItemsFn ( filteredItems ) ;
487493 }
488494 }
@@ -731,7 +737,7 @@ uis.controller('uiSelectCtrl',
731737 break ;
732738 case KEY . ENTER :
733739 if ( ctrl . open && ( ctrl . tagging . isActivated || ctrl . activeIndex >= 0 ) ) {
734- ctrl . select ( ctrl . items [ ctrl . activeIndex ] ) ; // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
740+ ctrl . select ( ctrl . items [ ctrl . activeIndex ] , ctrl . skipFocusser ) ; // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
735741 } else {
736742 ctrl . activate ( false , true ) ; //In case its the search input in 'multiple' mode
737743 }
@@ -931,6 +937,11 @@ uis.directive('uiSelect',
931937 }
932938 } ( ) ;
933939
940+ scope . $watch ( 'skipFocusser' , function ( ) {
941+ var skipFocusser = scope . $eval ( attrs . skipFocusser ) ;
942+ $select . skipFocusser = skipFocusser !== undefined ? skipFocusser : uiSelectConfig . skipFocusser ;
943+ } ) ;
944+
934945 $select . onSelectCallback = $parse ( attrs . onSelect ) ;
935946 $select . onRemoveCallback = $parse ( attrs . onRemove ) ;
936947
@@ -1041,11 +1052,16 @@ uis.directive('uiSelect',
10411052 }
10421053
10431054 if ( ! contains && ! $select . clickTriggeredSelect ) {
1044- //Will lose focus only with certain targets
1045- var focusableControls = [ 'input' , 'button' , 'textarea' , 'select' ] ;
1046- var targetController = angular . element ( e . target ) . controller ( 'uiSelect' ) ; //To check if target is other ui-select
1047- var skipFocusser = targetController && targetController !== $select ; //To check if target is other ui-select
1048- if ( ! skipFocusser ) skipFocusser = ~ focusableControls . indexOf ( e . target . tagName . toLowerCase ( ) ) ; //Check if target is input, button or textarea
1055+ var skipFocusser ;
1056+ if ( ! $select . skipFocusser ) {
1057+ //Will lose focus only with certain targets
1058+ var focusableControls = [ 'input' , 'button' , 'textarea' , 'select' ] ;
1059+ var targetController = angular . element ( e . target ) . controller ( 'uiSelect' ) ; //To check if target is other ui-select
1060+ skipFocusser = targetController && targetController !== $select ; //To check if target is other ui-select
1061+ if ( ! skipFocusser ) skipFocusser = ~ focusableControls . indexOf ( e . target . tagName . toLowerCase ( ) ) ; //Check if target is input, button or textarea
1062+ } else {
1063+ skipFocusser = true ;
1064+ }
10491065 $select . close ( skipFocusser ) ;
10501066 scope . $digest ( ) ;
10511067 }
@@ -1580,9 +1596,19 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
15801596 stashArr = stashArr . slice ( 1 , stashArr . length ) ;
15811597 }
15821598 newItem = $select . tagging . fct ( $select . search ) ;
1583- newItem . isTag = true ;
1584- // verify the the tag doesn't match the value of an existing item
1585- if ( stashArr . filter ( function ( origItem ) { return angular . equals ( origItem , $select . tagging . fct ( $select . search ) ) ; } ) . length > 0 ) {
1599+ // verify the new tag doesn't match the value of a possible selection choice or an already selected item.
1600+ if (
1601+ stashArr . some ( function ( origItem ) {
1602+ return angular . equals ( origItem , $select . tagging . fct ( $select . search ) ) ;
1603+ } ) ||
1604+ $select . selected . some ( function ( origItem ) {
1605+ return angular . equals ( origItem , newItem ) ;
1606+ } )
1607+ ) {
1608+ scope . $evalAsync ( function ( ) {
1609+ $select . activeIndex = 0 ;
1610+ $select . items = items ;
1611+ } ) ;
15861612 return ;
15871613 }
15881614 newItem . isTag = true ;
@@ -1977,38 +2003,48 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
19772003
19782004
19792005 var match ;
1980- var isObjectCollection = / \( \s * ( [ \$ \w ] [ \$ \w ] * ) \s * , \s * ( [ \$ \w ] [ \$ \w ] * ) \s * \) / . test ( expression ) ;
2006+ // var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression);
19812007 // If an array is used as collection
19822008
19832009 // if (isObjectCollection){
1984- //00000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000556666660000077777777777755000000000000000000000088888880000000
1985- match = expression . match ( / ^ \s * (?: ( [ \s \S ] + ?) \s + a s \s + ) ? (?: ( [ \$ \w ] [ \$ \w ] * ) | (?: \( \s * ( [ \$ \w ] [ \$ \w ] * ) \s * , \s * ( [ \$ \w ] [ \$ \w ] * ) \s * \) ) ) \s + i n \s + ( ( [ \w \. ] + ) ? \s * ( | \s * [ \s \S ] + ?) ) ? (?: \s + t r a c k \s + b y \s + ( [ \s \S ] + ?) ) ? \s * $ / ) ;
2010+ // 000000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000055555555555000000000000000000000066666666600000000
2011+ match = expression . match ( / ^ \s * (?: ( [ \s \S ] + ?) \s + a s \s + ) ? (?: ( [ \$ \w ] [ \$ \w ] * ) | (?: \( \s * ( [ \$ \w ] [ \$ \w ] * ) \s * , \s * ( [ \$ \w ] [ \$ \w ] * ) \s * \) ) ) \s + i n \s + ( \s * [ \s \S ] + ?) ? (?: \s + t r a c k \s + b y \s + ( [ \s \S ] + ?) ) ? \s * $ / ) ;
19862012
19872013 // 1 Alias
19882014 // 2 Item
19892015 // 3 Key on (key,value)
19902016 // 4 Value on (key,value)
1991- // 5 Collection expresion (only used when using an array collection)
1992- // 6 Object that will be converted to Array when using (key,value) syntax
1993- // 7 Filters that will be applied to #6 when using (key,value) syntax
1994- // 8 Track by
2017+ // 5 Source expression (including filters)
2018+ // 6 Track by
19952019
19962020 if ( ! match ) {
19972021 throw uiSelectMinErr ( 'iexp' , "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'." ,
19982022 expression ) ;
19992023 }
2000- if ( ! match [ 6 ] && isObjectCollection ) {
2001- throw uiSelectMinErr ( 'iexp' , "Expected expression in form of '_item_ as (_key_, _item_) in _ObjCollection_ [ track by _id_]' but got '{0}'." ,
2002- expression ) ;
2024+
2025+ var source = match [ 5 ] ,
2026+ filters = '' ;
2027+
2028+ // When using (key,value) ui-select requires filters to be extracted, since the object
2029+ // is converted to an array for $select.items
2030+ // (in which case the filters need to be reapplied)
2031+ if ( match [ 3 ] ) {
2032+ // Remove any enclosing parenthesis
2033+ source = match [ 5 ] . replace ( / ( ^ \( ) | ( \) $ ) / g, '' ) ;
2034+ // match all after | but not after ||
2035+ var filterMatch = match [ 5 ] . match ( / ^ \s * (?: [ \s \S ] + ?) (?: [ ^ \| ] | \| \| ) + ( [ \s \S ] * ) \s * $ / ) ;
2036+ if ( filterMatch && filterMatch [ 1 ] . trim ( ) ) {
2037+ filters = filterMatch [ 1 ] ;
2038+ source = source . replace ( filters , '' ) ;
2039+ }
20032040 }
20042041
20052042 return {
20062043 itemName : match [ 4 ] || match [ 2 ] , // (lhs) Left-hand side,
20072044 keyName : match [ 3 ] , //for (key, value) syntax
2008- source : $parse ( ! match [ 3 ] ? match [ 5 ] : match [ 6 ] ) ,
2009- sourceName : match [ 6 ] ,
2010- filters : match [ 7 ] ,
2011- trackByExp : match [ 8 ] ,
2045+ source : $parse ( source ) ,
2046+ filters : filters ,
2047+ trackByExp : match [ 6 ] ,
20122048 modelMapper : $parse ( match [ 1 ] || match [ 4 ] || match [ 2 ] ) ,
20132049 repeatExpression : function ( grouped ) {
20142050 var expression = this . itemName + ' in ' + ( grouped ? '$group.items' : '$select.items' ) ;
@@ -2028,7 +2064,7 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
20282064} ] ) ;
20292065
20302066} ( ) ) ;
2031- angular . module ( "ui.select" ) . run ( [ "$templateCache" , function ( $templateCache ) { $templateCache . put ( "bootstrap/choices.tpl.html" , "<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" role=\"listbox\" ng-show=\"$select.items.length > 0 \"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>" ) ;
2067+ angular . module ( "ui.select" ) . run ( [ "$templateCache" , function ( $templateCache ) { $templateCache . put ( "bootstrap/choices.tpl.html" , "<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" role=\"listbox\" ng-show=\"$select.open \"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>" ) ;
20322068$templateCache . put ( "bootstrap/match-multiple.tpl.html" , "<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><span class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\"> ×</span> <span uis-transclude-append=\"\"></span></span></span></span>" ) ;
20332069$templateCache . put ( "bootstrap/match.tpl.html" , "<div class=\"ui-select-match\" ng-hide=\"$select.open\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\"><span tabindex=\"-1\" class=\"btn btn-default form-control ui-select-toggle\" aria-label=\"{{ $select.baseTitle }} activate\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" style=\"outline: 0;\"><span ng-show=\"$select.isEmpty()\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"ui-select-match-text pull-left\" ng-class=\"{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}\" ng-transclude=\"\"></span> <i class=\"caret pull-right\" ng-click=\"$select.toggle($event)\"></i> <a ng-show=\"$select.allowClear && !$select.isEmpty()\" aria-label=\"{{ $select.baseTitle }} clear\" style=\"margin-right: 10px\" ng-click=\"$select.clear($event)\" class=\"btn btn-xs btn-link pull-right\"><i class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></i></a></span></div>" ) ;
20342070$templateCache . put ( "bootstrap/select-multiple.tpl.html" , "<div class=\"ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control\" ng-class=\"{open: $select.open}\"><div><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"false\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search input-xs\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\" role=\"combobox\" aria-label=\"{{ $select.baseTitle }}\" ondrop=\"return false;\"></div><div class=\"ui-select-choices\"></div></div>" ) ;
0 commit comments