|
1 | 1 | /*!
|
2 | 2 | * ui-select
|
3 | 3 | * http://github.com/angular-ui/ui-select
|
4 |
| - * Version: 0.7.0 - 2014-10-06T12:29:59.829Z |
| 4 | + * Version: 0.8.3 - 2014-10-14T18:22:05.432Z |
5 | 5 | * License: MIT
|
6 | 6 | */
|
7 | 7 |
|
|
27 | 27 | END: 35,
|
28 | 28 | BACKSPACE: 8,
|
29 | 29 | DELETE: 46,
|
| 30 | + COMMAND: 91, |
30 | 31 | isControl: function (e) {
|
31 | 32 | var k = e.which;
|
32 | 33 | switch (k) {
|
| 34 | + case KEY.COMMAND: |
33 | 35 | case KEY.SHIFT:
|
34 | 36 | case KEY.CTRL:
|
35 | 37 | case KEY.ALT:
|
|
190 | 192 | ctrl.activate = function(initSearchValue, avoidReset) {
|
191 | 193 | if (!ctrl.disabled && !ctrl.open) {
|
192 | 194 | if(!avoidReset) _resetSearchInput();
|
| 195 | + ctrl.focusser.prop('disabled', true); //Will reactivate it on .close() |
193 | 196 | ctrl.open = true;
|
194 | 197 | ctrl.activeMatchIndex = -1;
|
195 | 198 |
|
|
269 | 272 | if (ctrl.multiple){
|
270 | 273 | //Remove already selected items
|
271 | 274 | $scope.$watchCollection('$select.selected', function(selectedItems){
|
272 |
| - if (!selectedItems) return; |
273 | 275 | var data = ctrl.parserResult.source($scope);
|
274 |
| - var filteredItems = data.filter(function(i) {return selectedItems.indexOf(i) < 0;}); |
275 |
| - setItemsFn(filteredItems); |
| 276 | + if (!selectedItems.length) { |
| 277 | + setItemsFn(data); |
| 278 | + }else{ |
| 279 | + var filteredItems = data.filter(function(i) {return selectedItems.indexOf(i) < 0;}); |
| 280 | + setItemsFn(filteredItems); |
| 281 | + } |
| 282 | + ctrl.sizeSearchInput(); |
276 | 283 | });
|
277 | 284 | }
|
278 | 285 |
|
|
305 | 312 | };
|
306 | 313 |
|
307 | 314 | ctrl.isActive = function(itemScope) {
|
| 315 | +<<<<<<< HEAD |
308 | 316 | if ( typeof itemScope[ctrl.itemProperty] === 'undefined') {
|
309 | 317 | return false;
|
310 | 318 | }
|
| 319 | +======= |
| 320 | + return ctrl.open && ctrl.items.indexOf(itemScope[ctrl.itemProperty]) === ctrl.activeIndex; |
| 321 | +>>>>>>> master |
311 | 322 | };
|
312 | 323 |
|
313 | 324 | ctrl.isDisabled = function(itemScope) {
|
| 325 | + |
| 326 | + if (!ctrl.open) return; |
| 327 | + |
314 | 328 | var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
|
315 | 329 | var isDisabled = false;
|
316 | 330 | var item;
|
|
325 | 339 | };
|
326 | 340 |
|
327 | 341 | // When the user clicks on an item inside the dropdown
|
328 |
| - ctrl.select = function(item) { |
329 |
| - |
330 |
| - if (!item || !item._uiSelectChoiceDisabled) { |
331 |
| - if(ctrl.tagging.isActivated && !item && ctrl.search.length > 0) { |
332 |
| - // create new item on the fly |
333 |
| - item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search; |
334 |
| - } |
| 342 | + ctrl.select = function(item, skipFocusser) { |
335 | 343 |
|
| 344 | + if (item === undefined || !item._uiSelectChoiceDisabled) { |
336 | 345 | var locals = {};
|
337 | 346 | locals[ctrl.parserResult.itemName] = item;
|
338 | 347 |
|
|
347 | 356 | } else {
|
348 | 357 | ctrl.selected = item;
|
349 | 358 | }
|
350 |
| - ctrl.close(); |
| 359 | + ctrl.close(skipFocusser); |
351 | 360 | }
|
352 | 361 | };
|
353 | 362 |
|
354 | 363 | // Closes the dropdown
|
355 |
| - ctrl.close = function() { |
356 |
| - if (ctrl.open) { |
357 |
| - _resetSearchInput(); |
358 |
| - ctrl.open = false; |
| 364 | + ctrl.close = function(skipFocusser) { |
| 365 | + if (!ctrl.open) return; |
| 366 | + _resetSearchInput(); |
| 367 | + ctrl.open = false; |
| 368 | + if (!ctrl.multiple){ |
359 | 369 | $timeout(function(){
|
360 |
| - ctrl.focusser[0].focus(); |
| 370 | + ctrl.focusser.prop('disabled', false); |
| 371 | + if (!skipFocusser) ctrl.focusser[0].focus(); |
361 | 372 | },0,false);
|
362 | 373 | }
|
363 | 374 | };
|
|
371 | 382 |
|
372 | 383 | // Remove item from multiple select
|
373 | 384 | ctrl.removeChoice = function(index){
|
| 385 | + var removedChoice = ctrl.selected[index]; |
| 386 | + var locals = {}; |
| 387 | + locals[ctrl.parserResult.itemName] = removedChoice; |
| 388 | + |
374 | 389 | ctrl.selected.splice(index, 1);
|
375 | 390 | ctrl.activeMatchIndex = -1;
|
376 | 391 | ctrl.sizeSearchInput();
|
| 392 | + |
| 393 | + ctrl.onRemoveCallback($scope, { |
| 394 | + $item: removedChoice, |
| 395 | + $model: ctrl.parserResult.modelMapper($scope, locals) |
| 396 | + }); |
377 | 397 | };
|
378 | 398 |
|
379 | 399 | ctrl.getPlaceholder = function(){
|
|
382 | 402 | return ctrl.placeholder;
|
383 | 403 | };
|
384 | 404 |
|
| 405 | + var containerSizeWatch; |
385 | 406 | ctrl.sizeSearchInput = function(){
|
386 | 407 | var input = _searchInput[0],
|
387 | 408 | container = _searchInput.parent().parent()[0];
|
388 | 409 | _searchInput.css('width','10px');
|
389 |
| - $timeout(function(){ |
| 410 | + var calculate = function(){ |
390 | 411 | var newWidth = container.clientWidth - input.offsetLeft - 10;
|
391 | 412 | if(newWidth < 50) newWidth = container.clientWidth;
|
392 | 413 | _searchInput.css('width',newWidth+'px');
|
| 414 | + }; |
| 415 | + $timeout(function(){ //Give tags time to render correctly |
| 416 | + if (container.clientWidth === 0 && !containerSizeWatch){ |
| 417 | + containerSizeWatch = $scope.$watch(function(){ return container.clientWidth;}, function(newValue){ |
| 418 | + if (newValue !== 0){ |
| 419 | + calculate(); |
| 420 | + containerSizeWatch(); |
| 421 | + containerSizeWatch = null; |
| 422 | + } |
| 423 | + }); |
| 424 | + }else if (!containerSizeWatch) { |
| 425 | + calculate(); |
| 426 | + } |
393 | 427 | }, 0, false);
|
394 | 428 | };
|
395 | 429 |
|
|
402 | 436 | break;
|
403 | 437 | case KEY.UP:
|
404 | 438 | if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode
|
405 |
| - else if (ctrl.activeIndex > 0 || (ctrl.search.length === 0 && ctrl.tagging.isActivated)) { ctrl.activeIndex--; } |
| 439 | + else if (ctrl.activeIndex > 0) { ctrl.activeIndex--; } |
406 | 440 | break;
|
407 | 441 | case KEY.TAB:
|
408 |
| - //TODO: Que hacemos en modo multiple? |
409 |
| - if (!ctrl.multiple) ctrl.select(ctrl.items[ctrl.activeIndex]); |
| 442 | + if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true); |
410 | 443 | break;
|
411 | 444 | case KEY.ENTER:
|
412 | 445 | if(ctrl.open){
|
|
500 | 533 | if(ctrl.multiple && KEY.isHorizontalMovement(key)){
|
501 | 534 | processed = _handleMatchSelection(key);
|
502 | 535 | }
|
503 |
| - |
504 |
| - if (!processed && (ctrl.items.length > 0 || ctrl.tagging.isActivated)) { |
| 536 | + |
| 537 | + if (!processed && ctrl.items.length > 0) { |
505 | 538 | processed = _handleDropDownSelection(key);
|
506 | 539 | }
|
507 | 540 |
|
|
522 | 555 | _searchInput.on('blur', function() {
|
523 | 556 | $timeout(function() {
|
524 | 557 | ctrl.activeMatchIndex = -1;
|
525 |
| - ctrl.activeIndex = 0; |
526 | 558 | });
|
527 | 559 | });
|
528 | 560 |
|
|
583 | 615 |
|
584 | 616 | var searchInput = element.querySelectorAll('input.ui-select-search');
|
585 | 617 |
|
586 |
| - $select.multiple = angular.isDefined(attrs.multiple); |
| 618 | + $select.multiple = (angular.isDefined(attrs.multiple)) ? (attrs.multiple === '') ? true : (attrs.multiple.toLowerCase() === 'true') : false; |
587 | 619 |
|
588 | 620 | $select.onSelectCallback = $parse(attrs.onSelect);
|
| 621 | + $select.onRemoveCallback = $parse(attrs.onRemove); |
589 | 622 |
|
590 | 623 | //From view --> model
|
591 | 624 | ngModel.$parsers.unshift(function (inputValue) {
|
592 | 625 | var locals = {},
|
593 | 626 | result;
|
594 | 627 | if ($select.multiple){
|
595 | 628 | var resultMultiple = [];
|
596 |
| - for (var j = inputValue.length - 1; j >= 0; j--) { |
| 629 | + for (var j = $select.selected.length - 1; j >= 0; j--) { |
597 | 630 | locals = {};
|
598 |
| - locals[$select.parserResult.itemName] = inputValue[j]; |
| 631 | + locals[$select.parserResult.itemName] = $select.selected[j]; |
599 | 632 | result = $select.parserResult.modelMapper(scope, locals);
|
600 | 633 | resultMultiple.unshift(result);
|
601 | 634 | }
|
|
695 | 728 | e.preventDefault();
|
696 | 729 | e.stopPropagation();
|
697 | 730 | $select.select(undefined);
|
698 |
| - scope.$digest(); |
| 731 | + scope.$apply(); |
699 | 732 | return;
|
700 | 733 | }
|
701 | 734 |
|
|
743 | 776 | $select.resetSearchInput = resetSearchInput !== undefined ? resetSearchInput : true;
|
744 | 777 | });
|
745 | 778 |
|
746 |
| - attrs.$observe('tagging', function() { |
747 |
| - if(attrs.tagging !== undefined) |
748 |
| - { |
749 |
| - // $eval() is needed otherwise we get a string instead of a function or a boolean |
750 |
| - var taggingEval = scope.$eval(attrs.tagging); |
751 |
| - $select.tagging = {isActivated: true, fct: taggingEval !== true ? taggingEval : undefined}; |
752 |
| - } |
753 |
| - else |
754 |
| - { |
755 |
| - $select.tagging = {isActivated: false, fct: undefined}; |
756 |
| - } |
757 |
| - }); |
758 |
| - |
759 | 779 | if ($select.multiple){
|
760 |
| - scope.$watchCollection('$select.selected', function(newValue) { |
761 |
| - //On v1.2.19 the 2nd and 3rd parameteres are ignored |
762 |
| - //On v1.3.0-beta+ 3rd parameter (revalidate) is true, to force $parsers to recreate model |
763 |
| - ngModel.$setViewValue(newValue, null, true); |
| 780 | + scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) { |
| 781 | + if (oldValue != newValue) |
| 782 | + ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters |
| 783 | + }); |
| 784 | + scope.$watchCollection('$select.selected', function() { |
| 785 | + ngModel.$setViewValue(Date.now()); //Set timestamp as a unique string to force changes |
764 | 786 | });
|
765 | 787 | focusser.prop('disabled', true); //Focusser isn't needed if multiple
|
766 | 788 | }else{
|
|
888 | 910 |
|
889 | 911 | scope.$watch('$select.search', function(newValue) {
|
890 | 912 | if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
|
891 |
| - $select.activeIndex = $select.tagging.isActivated ? -1 : 0; |
| 913 | + $select.activeIndex = 0; |
892 | 914 | $select.refresh(attrs.refresh);
|
893 | 915 | });
|
894 | 916 |
|
|
929 | 951 | });
|
930 | 952 |
|
931 | 953 | if($select.multiple){
|
932 |
| - $select.sizeSearchInput(); |
| 954 | + $select.sizeSearchInput(); |
933 | 955 | }
|
934 | 956 |
|
935 | 957 | }
|
|
954 | 976 | }());
|
955 | 977 |
|
956 | 978 | angular.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=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\">{{$group.name}}</div><div class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><a href=\"javascript:void(0)\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>");
|
957 |
| -$templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><button style=\"margin-right: 3px;\" class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$select.activeMatchIndex === $index}\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$select.removeChoice($index)\"> ×</span> <span uis-transclude-append=\"\"></span></button></span></span>"); |
| 979 | +$templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><span style=\"margin-right: 3px;\" class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$select.activeMatchIndex === $index}\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$select.removeChoice($index)\"> ×</span> <span uis-transclude-append=\"\"></span></span></span></span>"); |
958 | 980 | $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-show=\"$select.searchEnabled && $select.isEmpty()\" class=\"text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" ng-transclude=\"\"></span> <span class=\"caret ui-select-toggle\" ng-click=\"$select.toggle($event)\"></span></button>");
|
959 | 981 | $templateCache.put("bootstrap/select-multiple.tpl.html","<div class=\"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=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search input-xs\" placeholder=\"{{$select.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div>");
|
960 | 982 | $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.searchEnabled && $select.open\"><div class=\"ui-select-choices\"></div></div>");
|
|
0 commit comments