@@ -561,6 +561,170 @@ uis.controller('uiSelectCtrl',
561
561
562
562
} ) ;
563
563
564
+ ctrl . searchInput . on ( 'keyup' , function ( e ) {
565
+
566
+ if ( ! KEY . isVerticalMovement ( e . which ) ) {
567
+ $scope . $evalAsync ( function ( ) {
568
+ ctrl . activeIndex = ctrl . taggingLabel === false ? - 1 : 0 ;
569
+ } ) ;
570
+ }
571
+ // Push a "create new" item into array if there is a search string
572
+ if ( ctrl . tagging . isActivated && ctrl . search . length > 0 ) {
573
+
574
+ // return early with these keys
575
+ if ( e . which === KEY . TAB || KEY . isControl ( e ) || KEY . isFunctionKey ( e ) || e . which === KEY . ESC || KEY . isVerticalMovement ( e . which ) ) {
576
+ return ;
577
+ }
578
+ // always reset the activeIndex to the first item when tagging
579
+ ctrl . activeIndex = ctrl . taggingLabel === false ? - 1 : 0 ;
580
+ // taggingLabel === false bypasses all of this
581
+ if ( ctrl . taggingLabel === false ) return ;
582
+
583
+ var items = angular . copy ( ctrl . items ) ;
584
+ var stashArr = angular . copy ( ctrl . items ) ;
585
+ var newItem ;
586
+ var item ;
587
+ var hasTag = false ;
588
+ var dupeIndex = - 1 ;
589
+ var tagItems ;
590
+ var tagItem ;
591
+
592
+ // case for object tagging via transform `ctrl.tagging.fct` function
593
+ if ( ctrl . tagging . fct !== undefined ) {
594
+ tagItems = ctrl . $filter ( 'filter' ) ( items , { 'isTag' : true } ) ;
595
+ if ( tagItems . length > 0 ) {
596
+ tagItem = tagItems [ 0 ] ;
597
+ }
598
+ // remove the first element, if it has the `isTag` prop we generate a new one with each keyup, shaving the previous
599
+ if ( items . length > 0 && tagItem ) {
600
+ hasTag = true ;
601
+ items = items . slice ( 1 , items . length ) ;
602
+ stashArr = stashArr . slice ( 1 , stashArr . length ) ;
603
+ }
604
+ newItem = ctrl . tagging . fct ( ctrl . search ) ;
605
+ // verify the new tag doesn't match the value of a possible selection choice or an already selected item.
606
+ if (
607
+ stashArr . some ( function ( origItem ) {
608
+ return angular . equals ( origItem , newItem ) ;
609
+ } ) ||
610
+ ( ctrl . selected && ctrl . selected . some ( function ( origItem ) {
611
+ return angular . equals ( origItem , newItem ) ;
612
+ } ) )
613
+ ) {
614
+ $scope . $evalAsync ( function ( ) {
615
+ ctrl . activeIndex = 0 ;
616
+ ctrl . items = items ;
617
+ } ) ;
618
+ return ;
619
+ }
620
+ if ( newItem ) newItem . isTag = true ;
621
+ // handle newItem string and stripping dupes in tagging string context
622
+ } else {
623
+ // find any tagging items already in the ctrl.items array and store them
624
+ tagItems = ctrl . $filter ( 'filter' ) ( items , function ( item ) {
625
+ return item . match ( ctrl . taggingLabel ) ;
626
+ } ) ;
627
+ if ( tagItems . length > 0 ) {
628
+ tagItem = tagItems [ 0 ] ;
629
+ }
630
+ item = items [ 0 ] ;
631
+ // remove existing tag item if found (should only ever be one tag item)
632
+ if ( item !== undefined && items . length > 0 && tagItem ) {
633
+ hasTag = true ;
634
+ items = items . slice ( 1 , items . length ) ;
635
+ stashArr = stashArr . slice ( 1 , stashArr . length ) ;
636
+ }
637
+ newItem = ctrl . search + ' ' + ctrl . taggingLabel ;
638
+ if ( _findApproxDupe ( ctrl . selected , ctrl . search ) > - 1 ) {
639
+ return ;
640
+ }
641
+ // verify the the tag doesn't match the value of an existing item from
642
+ // the searched data set or the items already selected
643
+ if ( _findCaseInsensitiveDupe ( stashArr . concat ( ctrl . selected ) ) ) {
644
+ // if there is a tag from prev iteration, strip it / queue the change
645
+ // and return early
646
+ if ( hasTag ) {
647
+ items = stashArr ;
648
+ $scope . $evalAsync ( function ( ) {
649
+ ctrl . activeIndex = 0 ;
650
+ ctrl . items = items ;
651
+ } ) ;
652
+ }
653
+ return ;
654
+ }
655
+ if ( _findCaseInsensitiveDupe ( stashArr ) ) {
656
+ // if there is a tag from prev iteration, strip it
657
+ if ( hasTag ) {
658
+ ctrl . items = stashArr . slice ( 1 , stashArr . length ) ;
659
+ }
660
+ return ;
661
+ }
662
+ }
663
+ if ( hasTag ) dupeIndex = _findApproxDupe ( ctrl . selected , newItem ) ;
664
+ // dupe found, shave the first item
665
+ if ( dupeIndex > - 1 ) {
666
+ items = items . slice ( dupeIndex + 1 , items . length - 1 ) ;
667
+ } else {
668
+ items = [ ] ;
669
+ if ( newItem ) items . push ( newItem ) ;
670
+ items = items . concat ( stashArr ) ;
671
+ }
672
+ $scope . $evalAsync ( function ( ) {
673
+ ctrl . activeIndex = 0 ;
674
+ ctrl . items = items ;
675
+
676
+ if ( ctrl . isGrouped ) {
677
+ // update item references in groups, so that indexOf will work after angular.copy
678
+ var itemsWithoutTag = newItem ? items . slice ( 1 ) : items ;
679
+ ctrl . setItemsFn ( itemsWithoutTag ) ;
680
+ if ( newItem ) {
681
+ // add tag item as a new group
682
+ ctrl . items . unshift ( newItem ) ;
683
+ ctrl . groups . unshift ( { name : '' , items : [ newItem ] , tagging : true } ) ;
684
+ }
685
+ }
686
+ } ) ;
687
+ }
688
+ } ) ;
689
+ function _findCaseInsensitiveDupe ( arr ) {
690
+ if ( arr === undefined || ctrl . search === undefined ) {
691
+ return false ;
692
+ }
693
+ var hasDupe = arr . filter ( function ( origItem ) {
694
+ if ( ctrl . search . toUpperCase ( ) === undefined || origItem === undefined ) {
695
+ return false ;
696
+ }
697
+ return origItem . toUpperCase ( ) === ctrl . search . toUpperCase ( ) ;
698
+ } ) . length > 0 ;
699
+
700
+ return hasDupe ;
701
+ }
702
+ function _findApproxDupe ( haystack , needle ) {
703
+ var dupeIndex = - 1 ;
704
+ if ( angular . isArray ( haystack ) ) {
705
+ var tempArr = angular . copy ( haystack ) ;
706
+ for ( var i = 0 ; i < tempArr . length ; i ++ ) {
707
+ // handle the simple string version of tagging
708
+ if ( ctrl . tagging . fct === undefined ) {
709
+ // search the array for the match
710
+ if ( tempArr [ i ] + ' ' + ctrl . taggingLabel === needle ) {
711
+ dupeIndex = i ;
712
+ }
713
+ // handle the object tagging implementation
714
+ } else {
715
+ var mockObj = tempArr [ i ] ;
716
+ if ( angular . isObject ( mockObj ) ) {
717
+ mockObj . isTag = true ;
718
+ }
719
+ if ( angular . equals ( mockObj , needle ) ) {
720
+ dupeIndex = i ;
721
+ }
722
+ }
723
+ }
724
+ }
725
+ return dupeIndex ;
726
+ }
727
+
564
728
ctrl . searchInput . on ( 'paste' , function ( e ) {
565
729
var data ;
566
730
0 commit comments