1
1
/*!
2
2
* ui-select
3
3
* 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
5
5
* License: MIT
6
6
*/
7
7
@@ -109,6 +109,7 @@ var uis = angular.module('ui.select', [])
109
109
placeholder : '' , // Empty by default, like HTML tag <select>
110
110
refreshDelay : 1000 , // In milliseconds
111
111
closeOnSelect : true ,
112
+ skipFocusser : false ,
112
113
dropdownPosition : 'auto' ,
113
114
generateId : function ( ) {
114
115
return latestId ++ ;
@@ -224,15 +225,15 @@ uis.directive('uiSelectChoices',
224
225
. attr ( 'ng-if' , '$select.open' ) ; //Prevent unnecessary watches when dropdown is closed
225
226
if ( $window . document . addEventListener ) { //crude way to exclude IE8, specifically, which also cannot capture events
226
227
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)' ) ;
228
229
}
229
230
230
231
var rowsInner = element . querySelectorAll ( '.ui-select-choices-row-inner' ) ;
231
232
if ( rowsInner . length !== 1 ) throw uiSelectMinErr ( 'rows' , "Expected 1 .ui-select-choices-row-inner but got '{0}'." , rowsInner . length ) ;
232
233
rowsInner . attr ( 'uis-transclude-append' , '' ) ; //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
233
234
if ( ! $window . document . addEventListener ) { //crude way to target IE8, specifically, which also cannot capture events - so event bindings must be here
234
235
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)' ) ;
236
237
}
237
238
238
239
$compile ( element , transcludeFn ) ( scope ) ; //Passing current transcludeFn to be able to append elements correctly from uisTranscludeAppend
@@ -279,6 +280,7 @@ uis.controller('uiSelectCtrl',
279
280
280
281
ctrl . removeSelected = false ; //If selected item(s) should be removed from dropdown list
281
282
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
282
284
ctrl . search = EMPTY_SEARCH ;
283
285
284
286
ctrl . activeIndex = 0 ; //Dropdown of choices
@@ -381,7 +383,7 @@ uis.controller('uiSelectCtrl',
381
383
}
382
384
383
385
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 ] ) ) {
385
387
ctrl . $animate . on ( 'enter' , container [ 0 ] , function ( elem , phase ) {
386
388
if ( phase === 'close' ) {
387
389
// Only focus input after the animation has finished
@@ -482,7 +484,11 @@ uis.controller('uiSelectCtrl',
482
484
ctrl . setItemsFn ( data ) ;
483
485
} else {
484
486
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
+ } ) ;
486
492
ctrl . setItemsFn ( filteredItems ) ;
487
493
}
488
494
}
@@ -731,7 +737,7 @@ uis.controller('uiSelectCtrl',
731
737
break ;
732
738
case KEY . ENTER :
733
739
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
735
741
} else {
736
742
ctrl . activate ( false , true ) ; //In case its the search input in 'multiple' mode
737
743
}
@@ -931,6 +937,11 @@ uis.directive('uiSelect',
931
937
}
932
938
} ( ) ;
933
939
940
+ scope . $watch ( 'skipFocusser' , function ( ) {
941
+ var skipFocusser = scope . $eval ( attrs . skipFocusser ) ;
942
+ $select . skipFocusser = skipFocusser !== undefined ? skipFocusser : uiSelectConfig . skipFocusser ;
943
+ } ) ;
944
+
934
945
$select . onSelectCallback = $parse ( attrs . onSelect ) ;
935
946
$select . onRemoveCallback = $parse ( attrs . onRemove ) ;
936
947
@@ -1041,11 +1052,16 @@ uis.directive('uiSelect',
1041
1052
}
1042
1053
1043
1054
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
+ }
1049
1065
$select . close ( skipFocusser ) ;
1050
1066
scope . $digest ( ) ;
1051
1067
}
@@ -1580,9 +1596,19 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1580
1596
stashArr = stashArr . slice ( 1 , stashArr . length ) ;
1581
1597
}
1582
1598
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
+ } ) ;
1586
1612
return ;
1587
1613
}
1588
1614
newItem . isTag = true ;
@@ -1977,38 +2003,48 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
1977
2003
1978
2004
1979
2005
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);
1981
2007
// If an array is used as collection
1982
2008
1983
2009
// 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 * $ / ) ;
1986
2012
1987
2013
// 1 Alias
1988
2014
// 2 Item
1989
2015
// 3 Key on (key,value)
1990
2016
// 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
1995
2019
1996
2020
if ( ! match ) {
1997
2021
throw uiSelectMinErr ( 'iexp' , "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'." ,
1998
2022
expression ) ;
1999
2023
}
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
+ }
2003
2040
}
2004
2041
2005
2042
return {
2006
2043
itemName : match [ 4 ] || match [ 2 ] , // (lhs) Left-hand side,
2007
2044
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 ] ,
2012
2048
modelMapper : $parse ( match [ 1 ] || match [ 4 ] || match [ 2 ] ) ,
2013
2049
repeatExpression : function ( grouped ) {
2014
2050
var expression = this . itemName + ' in ' + ( grouped ? '$group.items' : '$select.items' ) ;
@@ -2028,7 +2064,7 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
2028
2064
} ] ) ;
2029
2065
2030
2066
} ( ) ) ;
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>" ) ;
2032
2068
$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>" ) ;
2033
2069
$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>" ) ;
2034
2070
$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