11/*!
22 * ui-select
33 * http://github.com/angular-ui/ui-select
4- * Version: 0.3.1 - 2014-07-12T16:26:10.166Z
4+ * Version: 0.5.0 - 2014-07-30T04:47:33.132Z
55 * License: MIT
66 */
77
5151 * Original discussion about parsing "repeat" attribute instead of fully relying on ng-repeat:
5252 * https://github.com/angular-ui/ui-select/commit/5dd63ad#commitcomment-5504697
5353 */
54- . service ( 'RepeatParser' , [ 'uiSelectMinErr' , function ( uiSelectMinErr ) {
54+ . service ( 'RepeatParser' , [ 'uiSelectMinErr' , '$parse' , function ( uiSelectMinErr , $parse ) {
5555 var self = this ;
5656
5757 /**
5858 * Example:
5959 * expression = "address in addresses | filter: {street: $select.search} track by $index"
60- * lhs = "address",
61- * rhs = "addresses | filter: {street: $select.search}",
60+ * itemName = "address",
61+ * source = "addresses | filter: {street: $select.search}",
6262 * trackByExp = "$index",
63- * valueIdentifier = "address",
64- * keyIdentifier = undefined
6563 */
6664 self . parse = function ( expression ) {
67- if ( ! expression ) {
68- throw uiSelectMinErr ( 'repeat' , "Expected 'repeat' expression." ) ;
69- }
7065
71- var match = expression . match ( / ^ \s * ( [ \s \S ] + ?) \s + i n \s + ( [ \s \S ] + ?) (?: \s + t r a c k \s + b y \s + ( [ \s \S ] + ?) ) ? \s * $ / ) ;
66+ var match = expression . match ( / ^ \s * (?: ( [ \s \S ] + ? ) \s + a s \s + ) ? ( [ \s \S ] + ?) \s + i n \s + ( [ \s \S ] + ?) (?: \s + t r a c k \s + b y \s + ( [ \s \S ] + ?) ) ? \s * $ / ) ;
7267
7368 if ( ! match ) {
7469 throw uiSelectMinErr ( 'iexp' , "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'." ,
75- expression ) ;
76- }
77-
78- var lhs = match [ 1 ] ; // Left-hand side
79- var rhs = match [ 2 ] ; // Right-hand side
80- var trackByExp = match [ 3 ] ;
81-
82- match = lhs . match ( / ^ (?: ( [ \$ \w ] + ) | \( ( [ \$ \w ] + ) \s * , \s * ( [ \$ \w ] + ) \) ) $ / ) ;
83- if ( ! match ) {
84- throw uiSelectMinErr ( 'iidexp' , "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'." ,
85- lhs ) ;
70+ expression ) ;
8671 }
8772
88- // Unused for now
89- // var valueIdentifier = match[3] || match[1];
90- // var keyIdentifier = match[2];
91-
9273 return {
93- lhs : lhs ,
94- rhs : rhs ,
95- trackByExp : trackByExp
74+ itemName : match [ 2 ] , // (lhs) Left-hand side,
75+ source : match [ 3 ] , // (rhs) Right-hand side,
76+ trackByExp : match [ 4 ] ,
77+ modelMapper : $parse ( match [ 1 ] || match [ 2 ] )
9678 } ;
79+
9780 } ;
9881
9982 self . getGroupNgRepeatExpression = function ( ) {
10083 return '($group, $items) in $select.groups' ;
10184 } ;
10285
103- self . getNgRepeatExpression = function ( lhs , rhs , trackByExp , grouped ) {
104- var expression = lhs + ' in ' + ( grouped ? '$items' : rhs ) ;
86+ self . getNgRepeatExpression = function ( itemName , source , trackByExp , grouped ) {
87+ var expression = itemName + ' in ' + ( grouped ? '$items' : source ) ;
10588 if ( trackByExp ) {
10689 expression += ' track by ' + trackByExp ;
10790 }
188171 ctrl . items = items ;
189172 }
190173
191- var repeat = RepeatParser . parse ( repeatAttr ) ,
192- setItemsFn = groupByExp ? updateGroups : setPlainItems ;
174+ var setItemsFn = groupByExp ? updateGroups : setPlainItems ;
175+
176+ ctrl . parserResult = RepeatParser . parse ( repeatAttr ) ;
193177
194178 ctrl . isGrouped = ! ! groupByExp ;
195- ctrl . itemProperty = repeat . lhs ;
179+ ctrl . itemProperty = ctrl . parserResult . itemName ;
196180
197181 // See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259
198- $scope . $watchCollection ( repeat . rhs , function ( items ) {
182+ $scope . $watchCollection ( ctrl . parserResult . source , function ( items ) {
199183
200184 if ( items === undefined || items === null ) {
201185 // If the user specifies undefined or null => reset the collection
212196 }
213197
214198 } ) ;
199+
215200 } ;
216201
217202 var _refreshDelayPromise ;
299284
300285 $scope . $apply ( function ( ) {
301286 var processed = _onKeydown ( key ) ;
302- if ( processed ) {
287+ if ( processed && key != Key . Tab ) {
303288 e . preventDefault ( ) ;
304289 e . stopPropagation ( ) ;
305290 }
363348 var $select = ctrls [ 0 ] ;
364349 var ngModel = ctrls [ 1 ] ;
365350
351+ //From view --> model
352+ ngModel . $parsers . unshift ( function ( inputValue ) {
353+ var locals = { } ;
354+ locals [ $select . parserResult . itemName ] = inputValue ;
355+ var result = $select . parserResult . modelMapper ( scope , locals ) ;
356+ return result ;
357+ } ) ;
358+
359+ //From model --> view
360+ ngModel . $formatters . unshift ( function ( inputValue ) {
361+ var match = $select . parserResult . source . match ( / ^ \s * ( [ \S ] + ) .* $ / ) ;
362+ var data = scope [ match [ 1 ] ] ;
363+ if ( data ) {
364+ for ( var i = data . length - 1 ; i >= 0 ; i -- ) {
365+ var locals = { } ;
366+ locals [ $select . parserResult . itemName ] = data [ i ] ;
367+ var result = $select . parserResult . modelMapper ( scope , locals ) ;
368+ if ( result == inputValue ) {
369+ return data [ i ] ;
370+ }
371+ }
372+ }
373+ return inputValue ;
374+ } ) ;
375+
376+
366377 //Idea from: https://github.com/ivaynberg/select2/blob/79b5bf6db918d7560bdd959109b7bcfb47edaf43/select2.js#L1954
367378 var focusser = angular . element ( "<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' aria-haspopup='true' role='button' />" ) ;
368379 $compile ( focusser ) ( scope ) ;
381392 } ) ;
382393 focusser . bind ( "keydown" , function ( e ) {
383394
395+ if ( e . which === KEY . BACKSPACE ) {
396+ e . preventDefault ( ) ;
397+ e . stopPropagation ( ) ;
398+ $select . select ( undefined ) ;
399+ scope . $digest ( ) ;
400+ return ;
401+ }
402+
384403 if ( e . which === KEY . TAB || KEY . isControl ( e ) || KEY . isFunctionKey ( e ) || e . which === KEY . ESC ) {
385404 return ;
386405 }
396415
397416 focusser . bind ( "keyup input" , function ( e ) {
398417
399- if ( e . which === KEY . TAB || KEY . isControl ( e ) || KEY . isFunctionKey ( e ) || e . which === KEY . ESC || e . which == KEY . ENTER ) {
418+ if ( e . which === KEY . TAB || KEY . isControl ( e ) || KEY . isFunctionKey ( e ) || e . which === KEY . ESC || e . which == KEY . ENTER || e . which === KEY . BACKSPACE ) {
400419 return ;
401420 }
402421
510529 var transcluded = angular . element ( '<div>' ) . append ( clone ) ;
511530
512531 var transcludedMatch = transcluded . querySelectorAll ( '.ui-select-match' ) ;
532+ transcludedMatch . removeAttr ( 'ui-select-match' ) ; //To avoid loop in case directive as attr
513533 if ( transcludedMatch . length !== 1 ) {
514534 throw uiSelectMinErr ( 'transcluded' , "Expected 1 .ui-select-match but got '{0}'." , transcludedMatch . length ) ;
515535 }
516536 element . querySelectorAll ( '.ui-select-match' ) . replaceWith ( transcludedMatch ) ;
517537
518538 var transcludedChoices = transcluded . querySelectorAll ( '.ui-select-choices' ) ;
539+ transcludedChoices . removeAttr ( 'ui-select-choices' ) ; //To avoid loop in case directive as attr
519540 if ( transcludedChoices . length !== 1 ) {
520541 throw uiSelectMinErr ( 'transcluded' , "Expected 1 .ui-select-choices but got '{0}'." , transcludedChoices . length ) ;
521542 }
541562 } ,
542563
543564 compile : function ( tElement , tAttrs ) {
544- var repeat = RepeatParser . parse ( tAttrs . repeat ) ;
545- var groupByExp = tAttrs . groupBy ;
565+
566+ if ( ! tAttrs . repeat ) throw uiSelectMinErr ( 'repeat' , "Expected 'repeat' expression." ) ;
567+
546568 return function link ( scope , element , attrs , $select , transcludeFn ) {
569+
570+ // var repeat = RepeatParser.parse(attrs.repeat);
571+ var groupByExp = attrs . groupBy ;
572+
573+ $select . parseRepeatAttr ( attrs . repeat , groupByExp ) ; //Result ready at $select.parserResult
547574
548575 if ( groupByExp ) {
549576 var groups = element . querySelectorAll ( '.ui-select-choices-group' ) ;
556583 throw uiSelectMinErr ( 'rows' , "Expected 1 .ui-select-choices-row but got '{0}'." , choices . length ) ;
557584 }
558585
559- choices . attr ( 'ng-repeat' , RepeatParser . getNgRepeatExpression ( repeat . lhs , '$select.items' , repeat . trackByExp , groupByExp ) )
560- . attr ( 'ng-mouseenter' , '$select.setActiveItem(' + repeat . lhs + ')' )
561- . attr ( 'ng-click' , '$select.select(' + repeat . lhs + ')' ) ;
562-
586+ choices . attr ( 'ng-repeat' , RepeatParser . getNgRepeatExpression ( $select . parserResult . itemName , '$select.items' , $select . parserResult . trackByExp , groupByExp ) )
587+ . attr ( 'ng-mouseenter' , '$select.setActiveItem(' + $select . parserResult . itemName + ')' )
588+ . attr ( 'ng-click' , '$select.select(' + $select . parserResult . itemName + ')' ) ;
563589
564590 transcludeFn ( function ( clone ) {
565591 var rowsInner = element . querySelectorAll ( '.ui-select-choices-row-inner' ) ;
570596 $compile ( element ) ( scope ) ;
571597 } ) ;
572598
573- $select . parseRepeatAttr ( attrs . repeat , groupByExp ) ;
574-
575599 scope . $watch ( '$select.search' , function ( ) {
576600 $select . activeIndex = 0 ;
577601 $select . refresh ( attrs . refresh ) ;
626650angular . module ( "ui.select" ) . run ( [ "$templateCache" , function ( $templateCache ) { $templateCache . put ( "bootstrap/choices.tpl.html" , "<ul class=\"ui-select-choices ui-select-choices-content dropdown-menu\" role=\"menu\" aria-labelledby=\"dLabel\" ng-show=\"$select.items.length > 0\"><li class=\"ui-select-choices-group\"><div class=\"divider\" ng-show=\"$index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\">{{$group}}</div><div class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this)}\"><a href=\"javascript:void(0)\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>" ) ;
627651$templateCache . put ( "bootstrap/match.tpl.html" , "<button type=\"button\" class=\"btn btn-default form-control ui-select-match\" tabindex=\"-1\" ng-hide=\"$select.open\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\" ;=\"\" ng-click=\"$select.activate()\"><span ng-hide=\"$select.selected !== undefined\" class=\"text-muted\">{{$select.placeholder}}</span> <span ng-show=\"$select.selected !== undefined\" ng-transclude=\"\"></span> <span class=\"caret\"></span></button>" ) ;
628652$templateCache . put ( "bootstrap/select.tpl.html" , "<div class=\"ui-select-bootstrap dropdown\" ng-class=\"{open: $select.open}\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" tabindex=\"-1\" class=\"form-control ui-select-search\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-show=\"$select.open\"><div class=\"ui-select-choices\"></div></div>" ) ;
629- $templateCache . put ( "select2/choices.tpl.html" , "<ul class=\"ui-select-choices ui-select-choices-content select2-results\"><li class=\"ui-select-choices-group\" ng-class=\"{\'select2-result-with-children\': $select.isGrouped}\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label select2-result-label\">{{$group}}</div><ul class=\"select2-result-sub\"><li class=\"ui-select-choices-row\" ng-class=\"{\'select2-highlighted\': $select.isActive(this)}\"><div class=\"select2-result-label ui-select-choices-row-inner\"></div></li></ul></li></ul>" ) ;
630- $templateCache . put ( "select2/match.tpl.html" , "<a class=\"select2-choice ui-select-match\" ng-class=\"{\'select2-default\': $select.selected === undefined}\" ng-click=\"$select.activate()\"><span ng-hide=\"$select.selected !== undefined\" class=\"select2-chosen\">{{$select.placeholder}}</span> <span ng-show=\"$select.selected !== undefined\" class=\"select2-chosen\" ng-transclude=\"\"></span> <span class=\"select2-arrow\"><b></b></span></a>" ) ;
631- $templateCache . put ( "select2/select.tpl.html" , "<div class=\"select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open\': $select.open,\n \'select2-container-disabled\': $select.disabled,\n \'select2-container-active\': $select.focus }\"><div class=\"ui-select-match\"></div><div class=\"select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"select2-search\"><input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div></div>" ) ;
632653$templateCache . put ( "selectize/choices.tpl.html" , "<div ng-show=\"$select.open\" class=\"ui-select-choices selectize-dropdown single\"><div class=\"ui-select-choices-content selectize-dropdown-content\"><div class=\"ui-select-choices-group optgroup\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\">{{$group}}</div><div class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>" ) ;
633654$templateCache . put ( "selectize/match.tpl.html" , "<div ng-hide=\"$select.open || $select.selected === undefined\" class=\"ui-select-match\" ng-transclude=\"\"></div>" ) ;
634- $templateCache . put ( "selectize/select.tpl.html" , "<div class=\"selectize-control single\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.activate()\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"$select.selected && !$select.open\" ng-disabled=\"$select.disabled\"></div><div class=\"ui-select-choices\"></div></div>" ) ; } ] ) ;
655+ $templateCache . put ( "selectize/select.tpl.html" , "<div class=\"selectize-control single\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.activate()\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"$select.selected && !$select.open\" ng-disabled=\"$select.disabled\"></div><div class=\"ui-select-choices\"></div></div>" ) ;
656+ $templateCache . put ( "select2/choices.tpl.html" , "<ul class=\"ui-select-choices ui-select-choices-content select2-results\"><li class=\"ui-select-choices-group\" ng-class=\"{\'select2-result-with-children\': $select.isGrouped}\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label select2-result-label\">{{$group}}</div><ul ng-class=\"{\'select2-result-sub\': $select.isGrouped, \'select2-result-single\': !$select.isGrouped}\"><li class=\"ui-select-choices-row\" ng-class=\"{\'select2-highlighted\': $select.isActive(this)}\"><div class=\"select2-result-label ui-select-choices-row-inner\"></div></li></ul></li></ul>" ) ;
657+ $templateCache . put ( "select2/match.tpl.html" , "<a class=\"select2-choice ui-select-match\" ng-class=\"{\'select2-default\': $select.selected === undefined}\" ng-click=\"$select.activate()\"><span ng-hide=\"$select.selected !== undefined\" class=\"select2-chosen\">{{$select.placeholder}}</span> <span ng-show=\"$select.selected !== undefined\" class=\"select2-chosen\" ng-transclude=\"\"></span> <span class=\"select2-arrow\"><b></b></span></a>" ) ;
658+ $templateCache . put ( "select2/select.tpl.html" , "<div class=\"select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open\': $select.open,\n \'select2-container-disabled\': $select.disabled,\n \'select2-container-active\': $select.focus }\"><div class=\"ui-select-match\"></div><div class=\"select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"select2-search\"><input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div></div>" ) ; } ] ) ;
0 commit comments