bard-tag_field 0.4.2 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -543,459 +543,459 @@ class Taggle {
543
543
  }
544
544
  }
545
545
 
546
- /**
547
- * Copyright (c) 2016 Denis Taran
548
- *
549
- * Homepage: https://smartscheduling.com/en/documentation/autocomplete
550
- * Source: https://github.com/denis-taran/autocomplete
551
- *
552
- * MIT License
553
- */
554
- function autocomplete(settings) {
555
- // just an alias to minimize JS file size
556
- var doc = document;
557
- var container = settings.container || doc.createElement('div');
558
- var preventSubmit = settings.preventSubmit || 0 /* Never */;
559
- container.id = container.id || 'autocomplete-' + uid();
560
- var containerStyle = container.style;
561
- var debounceWaitMs = settings.debounceWaitMs || 0;
562
- var disableAutoSelect = settings.disableAutoSelect || false;
563
- var customContainerParent = container.parentElement;
564
- var items = [];
565
- var inputValue = '';
566
- var minLen = 2;
567
- var showOnFocus = settings.showOnFocus;
568
- var selected;
569
- var fetchCounter = 0;
570
- var debounceTimer;
571
- var destroyed = false;
572
- // Fixes #104: autocomplete selection is broken on Firefox for Android
573
- var suppressAutocomplete = false;
574
- if (settings.minLength !== undefined) {
575
- minLen = settings.minLength;
576
- }
577
- if (!settings.input) {
578
- throw new Error('input undefined');
579
- }
580
- var input = settings.input;
581
- container.className = [container.className, 'autocomplete', settings.className || ''].join(' ').trim();
582
- container.setAttribute('role', 'listbox');
583
- input.setAttribute('role', 'combobox');
584
- input.setAttribute('aria-expanded', 'false');
585
- input.setAttribute('aria-autocomplete', 'list');
586
- input.setAttribute('aria-controls', container.id);
587
- input.setAttribute('aria-owns', container.id);
588
- input.setAttribute('aria-activedescendant', '');
589
- input.setAttribute('aria-haspopup', 'listbox');
590
- // IOS implementation for fixed positioning has many bugs, so we will use absolute positioning
591
- containerStyle.position = 'absolute';
592
- /**
593
- * Generate a very complex textual ID that greatly reduces the chance of a collision with another ID or text.
594
- */
595
- function uid() {
596
- return Date.now().toString(36) + Math.random().toString(36).substring(2);
597
- }
598
- /**
599
- * Detach the container from DOM
600
- */
601
- function detach() {
602
- var parent = container.parentNode;
603
- if (parent) {
604
- parent.removeChild(container);
605
- }
606
- }
607
- /**
608
- * Clear debouncing timer if assigned
609
- */
610
- function clearDebounceTimer() {
611
- if (debounceTimer) {
612
- window.clearTimeout(debounceTimer);
613
- }
614
- }
615
- /**
616
- * Attach the container to DOM
617
- */
618
- function attach() {
619
- if (!container.parentNode) {
620
- (customContainerParent || doc.body).appendChild(container);
621
- }
622
- }
623
- /**
624
- * Check if container for autocomplete is displayed
625
- */
626
- function containerDisplayed() {
627
- return !!container.parentNode;
628
- }
629
- /**
630
- * Clear autocomplete state and hide container
631
- */
632
- function clear() {
633
- // prevent the update call if there are pending AJAX requests
634
- fetchCounter++;
635
- items = [];
636
- inputValue = '';
637
- selected = undefined;
638
- input.setAttribute('aria-activedescendant', '');
639
- input.setAttribute('aria-expanded', 'false');
640
- detach();
641
- }
642
- /**
643
- * Update autocomplete position
644
- */
645
- function updatePosition() {
646
- if (!containerDisplayed()) {
647
- return;
648
- }
649
- input.setAttribute('aria-expanded', 'true');
650
- containerStyle.height = 'auto';
651
- containerStyle.width = input.offsetWidth + 'px';
652
- var maxHeight = 0;
653
- var inputRect;
654
- function calc() {
655
- var docEl = doc.documentElement;
656
- var clientTop = docEl.clientTop || doc.body.clientTop || 0;
657
- var clientLeft = docEl.clientLeft || doc.body.clientLeft || 0;
658
- var scrollTop = window.pageYOffset || docEl.scrollTop;
659
- var scrollLeft = window.pageXOffset || docEl.scrollLeft;
660
- inputRect = input.getBoundingClientRect();
661
- var top = inputRect.top + input.offsetHeight + scrollTop - clientTop;
662
- var left = inputRect.left + scrollLeft - clientLeft;
663
- containerStyle.top = top + 'px';
664
- containerStyle.left = left + 'px';
665
- maxHeight = window.innerHeight - (inputRect.top + input.offsetHeight);
666
- if (maxHeight < 0) {
667
- maxHeight = 0;
668
- }
669
- containerStyle.top = top + 'px';
670
- containerStyle.bottom = '';
671
- containerStyle.left = left + 'px';
672
- containerStyle.maxHeight = maxHeight + 'px';
673
- }
674
- // the calc method must be called twice, otherwise the calculation may be wrong on resize event (chrome browser)
675
- calc();
676
- calc();
677
- if (settings.customize && inputRect) {
678
- settings.customize(input, inputRect, container, maxHeight);
679
- }
680
- }
681
- /**
682
- * Redraw the autocomplete div element with suggestions
683
- */
684
- function update() {
685
- container.textContent = '';
686
- input.setAttribute('aria-activedescendant', '');
687
- // function for rendering autocomplete suggestions
688
- var render = function (item, _, __) {
689
- var itemElement = doc.createElement('div');
690
- itemElement.textContent = item.label || '';
691
- return itemElement;
692
- };
693
- if (settings.render) {
694
- render = settings.render;
695
- }
696
- // function to render autocomplete groups
697
- var renderGroup = function (groupName, _) {
698
- var groupDiv = doc.createElement('div');
699
- groupDiv.textContent = groupName;
700
- return groupDiv;
701
- };
702
- if (settings.renderGroup) {
703
- renderGroup = settings.renderGroup;
704
- }
705
- var fragment = doc.createDocumentFragment();
706
- var prevGroup = uid();
707
- items.forEach(function (item, index) {
708
- if (item.group && item.group !== prevGroup) {
709
- prevGroup = item.group;
710
- var groupDiv = renderGroup(item.group, inputValue);
711
- if (groupDiv) {
712
- groupDiv.className += ' group';
713
- fragment.appendChild(groupDiv);
714
- }
715
- }
716
- var div = render(item, inputValue, index);
717
- if (div) {
718
- div.id = container.id + "_" + index;
719
- div.setAttribute('role', 'option');
720
- div.addEventListener('click', function (ev) {
721
- suppressAutocomplete = true;
722
- try {
723
- settings.onSelect(item, input);
724
- }
725
- finally {
726
- suppressAutocomplete = false;
727
- }
728
- clear();
729
- ev.preventDefault();
730
- ev.stopPropagation();
731
- });
732
- if (item === selected) {
733
- div.className += ' selected';
734
- div.setAttribute('aria-selected', 'true');
735
- input.setAttribute('aria-activedescendant', div.id);
736
- }
737
- fragment.appendChild(div);
738
- }
739
- });
740
- container.appendChild(fragment);
741
- if (items.length < 1) {
742
- if (settings.emptyMsg) {
743
- var empty = doc.createElement('div');
744
- empty.id = container.id + "_" + uid();
745
- empty.className = 'empty';
746
- empty.textContent = settings.emptyMsg;
747
- container.appendChild(empty);
748
- input.setAttribute('aria-activedescendant', empty.id);
749
- }
750
- else {
751
- clear();
752
- return;
753
- }
754
- }
755
- attach();
756
- updatePosition();
757
- updateScroll();
758
- }
759
- function updateIfDisplayed() {
760
- if (containerDisplayed()) {
761
- update();
762
- }
763
- }
764
- function resizeEventHandler() {
765
- updateIfDisplayed();
766
- }
767
- function scrollEventHandler(e) {
768
- if (e.target !== container) {
769
- updateIfDisplayed();
770
- }
771
- else {
772
- e.preventDefault();
773
- }
774
- }
775
- function inputEventHandler() {
776
- if (!suppressAutocomplete) {
777
- fetch(0 /* Keyboard */);
778
- }
779
- }
780
- /**
781
- * Automatically move scroll bar if selected item is not visible
782
- */
783
- function updateScroll() {
784
- var elements = container.getElementsByClassName('selected');
785
- if (elements.length > 0) {
786
- var element = elements[0];
787
- // make group visible
788
- var previous = element.previousElementSibling;
789
- if (previous && previous.className.indexOf('group') !== -1 && !previous.previousElementSibling) {
790
- element = previous;
791
- }
792
- if (element.offsetTop < container.scrollTop) {
793
- container.scrollTop = element.offsetTop;
794
- }
795
- else {
796
- var selectBottom = element.offsetTop + element.offsetHeight;
797
- var containerBottom = container.scrollTop + container.offsetHeight;
798
- if (selectBottom > containerBottom) {
799
- container.scrollTop += selectBottom - containerBottom;
800
- }
801
- }
802
- }
803
- }
804
- function selectPreviousSuggestion() {
805
- var index = items.indexOf(selected);
806
- selected = index === -1
807
- ? undefined
808
- : items[(index + items.length - 1) % items.length];
809
- updateSelectedSuggestion(index);
810
- }
811
- function selectNextSuggestion() {
812
- var index = items.indexOf(selected);
813
- selected = items.length < 1
814
- ? undefined
815
- : index === -1
816
- ? items[0]
817
- : items[(index + 1) % items.length];
818
- updateSelectedSuggestion(index);
819
- }
820
- function updateSelectedSuggestion(index) {
821
- if (items.length > 0) {
822
- unselectSuggestion(index);
823
- selectSuggestion(items.indexOf(selected));
824
- updateScroll();
825
- }
826
- }
827
- function selectSuggestion(index) {
828
- var element = doc.getElementById(container.id + "_" + index);
829
- if (element) {
830
- element.classList.add('selected');
831
- element.setAttribute('aria-selected', 'true');
832
- input.setAttribute('aria-activedescendant', element.id);
833
- }
834
- }
835
- function unselectSuggestion(index) {
836
- var element = doc.getElementById(container.id + "_" + index);
837
- if (element) {
838
- element.classList.remove('selected');
839
- element.removeAttribute('aria-selected');
840
- input.removeAttribute('aria-activedescendant');
841
- }
842
- }
843
- function handleArrowAndEscapeKeys(ev, key) {
844
- var containerIsDisplayed = containerDisplayed();
845
- if (key === 'Escape') {
846
- clear();
847
- }
848
- else {
849
- if (!containerIsDisplayed || items.length < 1) {
850
- return;
851
- }
852
- key === 'ArrowUp'
853
- ? selectPreviousSuggestion()
854
- : selectNextSuggestion();
855
- }
856
- ev.preventDefault();
857
- if (containerIsDisplayed) {
858
- ev.stopPropagation();
859
- }
860
- }
861
- function handleEnterKey(ev) {
862
- if (selected) {
863
- if (preventSubmit === 2 /* OnSelect */) {
864
- ev.preventDefault();
865
- }
866
- suppressAutocomplete = true;
867
- try {
868
- settings.onSelect(selected, input);
869
- }
870
- finally {
871
- suppressAutocomplete = false;
872
- }
873
- clear();
874
- }
875
- if (preventSubmit === 1 /* Always */) {
876
- ev.preventDefault();
877
- }
878
- }
879
- function keydownEventHandler(ev) {
880
- var key = ev.key;
881
- switch (key) {
882
- case 'ArrowUp':
883
- case 'ArrowDown':
884
- case 'Escape':
885
- handleArrowAndEscapeKeys(ev, key);
886
- break;
887
- case 'Enter':
888
- handleEnterKey(ev);
889
- break;
890
- }
891
- }
892
- function focusEventHandler() {
893
- if (showOnFocus) {
894
- fetch(1 /* Focus */);
895
- }
896
- }
897
- function fetch(trigger) {
898
- if (input.value.length >= minLen || trigger === 1 /* Focus */) {
899
- clearDebounceTimer();
900
- debounceTimer = window.setTimeout(function () { return startFetch(input.value, trigger, input.selectionStart || 0); }, trigger === 0 /* Keyboard */ || trigger === 2 /* Mouse */ ? debounceWaitMs : 0);
901
- }
902
- else {
903
- clear();
904
- }
905
- }
906
- function startFetch(inputText, trigger, cursorPos) {
907
- if (destroyed)
908
- return;
909
- var savedFetchCounter = ++fetchCounter;
910
- settings.fetch(inputText, function (elements) {
911
- if (fetchCounter === savedFetchCounter && elements) {
912
- items = elements;
913
- inputValue = inputText;
914
- selected = (items.length < 1 || disableAutoSelect) ? undefined : items[0];
915
- update();
916
- }
917
- }, trigger, cursorPos);
918
- }
919
- function keyupEventHandler(e) {
920
- if (settings.keyup) {
921
- settings.keyup({
922
- event: e,
923
- fetch: function () { return fetch(0 /* Keyboard */); }
924
- });
925
- return;
926
- }
927
- if (!containerDisplayed() && e.key === 'ArrowDown') {
928
- fetch(0 /* Keyboard */);
929
- }
930
- }
931
- function clickEventHandler(e) {
932
- settings.click && settings.click({
933
- event: e,
934
- fetch: function () { return fetch(2 /* Mouse */); }
935
- });
936
- }
937
- function blurEventHandler() {
938
- // when an item is selected by mouse click, the blur event will be initiated before the click event and remove DOM elements,
939
- // so that the click event will never be triggered. In order to avoid this issue, DOM removal should be delayed.
940
- setTimeout(function () {
941
- if (doc.activeElement !== input) {
942
- clear();
943
- }
944
- }, 200);
945
- }
946
- function manualFetch() {
947
- startFetch(input.value, 3 /* Manual */, input.selectionStart || 0);
948
- }
949
- /**
950
- * Fixes #26: on long clicks focus will be lost and onSelect method will not be called
951
- */
952
- container.addEventListener('mousedown', function (evt) {
953
- evt.stopPropagation();
954
- evt.preventDefault();
955
- });
956
- /**
957
- * Fixes #30: autocomplete closes when scrollbar is clicked in IE
958
- * See: https://stackoverflow.com/a/9210267/13172349
959
- */
960
- container.addEventListener('focus', function () { return input.focus(); });
961
- // If the custom autocomplete container is already appended to the DOM during widget initialization, detach it.
962
- detach();
963
- /**
964
- * This function will remove DOM elements and clear event handlers
965
- */
966
- function destroy() {
967
- input.removeEventListener('focus', focusEventHandler);
968
- input.removeEventListener('keyup', keyupEventHandler);
969
- input.removeEventListener('click', clickEventHandler);
970
- input.removeEventListener('keydown', keydownEventHandler);
971
- input.removeEventListener('input', inputEventHandler);
972
- input.removeEventListener('blur', blurEventHandler);
973
- window.removeEventListener('resize', resizeEventHandler);
974
- doc.removeEventListener('scroll', scrollEventHandler, true);
975
- input.removeAttribute('role');
976
- input.removeAttribute('aria-expanded');
977
- input.removeAttribute('aria-autocomplete');
978
- input.removeAttribute('aria-controls');
979
- input.removeAttribute('aria-activedescendant');
980
- input.removeAttribute('aria-owns');
981
- input.removeAttribute('aria-haspopup');
982
- clearDebounceTimer();
983
- clear();
984
- destroyed = true;
985
- }
986
- // setup event handlers
987
- input.addEventListener('keyup', keyupEventHandler);
988
- input.addEventListener('click', clickEventHandler);
989
- input.addEventListener('keydown', keydownEventHandler);
990
- input.addEventListener('input', inputEventHandler);
991
- input.addEventListener('blur', blurEventHandler);
992
- input.addEventListener('focus', focusEventHandler);
993
- window.addEventListener('resize', resizeEventHandler);
994
- doc.addEventListener('scroll', scrollEventHandler, true);
995
- return {
996
- destroy: destroy,
997
- fetch: manualFetch
998
- };
546
+ /**
547
+ * Copyright (c) 2016 Denis Taran
548
+ *
549
+ * Homepage: https://smartscheduling.com/en/documentation/autocomplete
550
+ * Source: https://github.com/denis-taran/autocomplete
551
+ *
552
+ * MIT License
553
+ */
554
+ function autocomplete(settings) {
555
+ // just an alias to minimize JS file size
556
+ var doc = document;
557
+ var container = settings.container || doc.createElement('div');
558
+ var preventSubmit = settings.preventSubmit || 0 /* Never */;
559
+ container.id = container.id || 'autocomplete-' + uid();
560
+ var containerStyle = container.style;
561
+ var debounceWaitMs = settings.debounceWaitMs || 0;
562
+ var disableAutoSelect = settings.disableAutoSelect || false;
563
+ var customContainerParent = container.parentElement;
564
+ var items = [];
565
+ var inputValue = '';
566
+ var minLen = 2;
567
+ var showOnFocus = settings.showOnFocus;
568
+ var selected;
569
+ var fetchCounter = 0;
570
+ var debounceTimer;
571
+ var destroyed = false;
572
+ // Fixes #104: autocomplete selection is broken on Firefox for Android
573
+ var suppressAutocomplete = false;
574
+ if (settings.minLength !== undefined) {
575
+ minLen = settings.minLength;
576
+ }
577
+ if (!settings.input) {
578
+ throw new Error('input undefined');
579
+ }
580
+ var input = settings.input;
581
+ container.className = [container.className, 'autocomplete', settings.className || ''].join(' ').trim();
582
+ container.setAttribute('role', 'listbox');
583
+ input.setAttribute('role', 'combobox');
584
+ input.setAttribute('aria-expanded', 'false');
585
+ input.setAttribute('aria-autocomplete', 'list');
586
+ input.setAttribute('aria-controls', container.id);
587
+ input.setAttribute('aria-owns', container.id);
588
+ input.setAttribute('aria-activedescendant', '');
589
+ input.setAttribute('aria-haspopup', 'listbox');
590
+ // IOS implementation for fixed positioning has many bugs, so we will use absolute positioning
591
+ containerStyle.position = 'absolute';
592
+ /**
593
+ * Generate a very complex textual ID that greatly reduces the chance of a collision with another ID or text.
594
+ */
595
+ function uid() {
596
+ return Date.now().toString(36) + Math.random().toString(36).substring(2);
597
+ }
598
+ /**
599
+ * Detach the container from DOM
600
+ */
601
+ function detach() {
602
+ var parent = container.parentNode;
603
+ if (parent) {
604
+ parent.removeChild(container);
605
+ }
606
+ }
607
+ /**
608
+ * Clear debouncing timer if assigned
609
+ */
610
+ function clearDebounceTimer() {
611
+ if (debounceTimer) {
612
+ window.clearTimeout(debounceTimer);
613
+ }
614
+ }
615
+ /**
616
+ * Attach the container to DOM
617
+ */
618
+ function attach() {
619
+ if (!container.parentNode) {
620
+ (customContainerParent || doc.body).appendChild(container);
621
+ }
622
+ }
623
+ /**
624
+ * Check if container for autocomplete is displayed
625
+ */
626
+ function containerDisplayed() {
627
+ return !!container.parentNode;
628
+ }
629
+ /**
630
+ * Clear autocomplete state and hide container
631
+ */
632
+ function clear() {
633
+ // prevent the update call if there are pending AJAX requests
634
+ fetchCounter++;
635
+ items = [];
636
+ inputValue = '';
637
+ selected = undefined;
638
+ input.setAttribute('aria-activedescendant', '');
639
+ input.setAttribute('aria-expanded', 'false');
640
+ detach();
641
+ }
642
+ /**
643
+ * Update autocomplete position
644
+ */
645
+ function updatePosition() {
646
+ if (!containerDisplayed()) {
647
+ return;
648
+ }
649
+ input.setAttribute('aria-expanded', 'true');
650
+ containerStyle.height = 'auto';
651
+ containerStyle.width = input.offsetWidth + 'px';
652
+ var maxHeight = 0;
653
+ var inputRect;
654
+ function calc() {
655
+ var docEl = doc.documentElement;
656
+ var clientTop = docEl.clientTop || doc.body.clientTop || 0;
657
+ var clientLeft = docEl.clientLeft || doc.body.clientLeft || 0;
658
+ var scrollTop = window.pageYOffset || docEl.scrollTop;
659
+ var scrollLeft = window.pageXOffset || docEl.scrollLeft;
660
+ inputRect = input.getBoundingClientRect();
661
+ var top = inputRect.top + input.offsetHeight + scrollTop - clientTop;
662
+ var left = inputRect.left + scrollLeft - clientLeft;
663
+ containerStyle.top = top + 'px';
664
+ containerStyle.left = left + 'px';
665
+ maxHeight = window.innerHeight - (inputRect.top + input.offsetHeight);
666
+ if (maxHeight < 0) {
667
+ maxHeight = 0;
668
+ }
669
+ containerStyle.top = top + 'px';
670
+ containerStyle.bottom = '';
671
+ containerStyle.left = left + 'px';
672
+ containerStyle.maxHeight = maxHeight + 'px';
673
+ }
674
+ // the calc method must be called twice, otherwise the calculation may be wrong on resize event (chrome browser)
675
+ calc();
676
+ calc();
677
+ if (settings.customize && inputRect) {
678
+ settings.customize(input, inputRect, container, maxHeight);
679
+ }
680
+ }
681
+ /**
682
+ * Redraw the autocomplete div element with suggestions
683
+ */
684
+ function update() {
685
+ container.textContent = '';
686
+ input.setAttribute('aria-activedescendant', '');
687
+ // function for rendering autocomplete suggestions
688
+ var render = function (item, _, __) {
689
+ var itemElement = doc.createElement('div');
690
+ itemElement.textContent = item.label || '';
691
+ return itemElement;
692
+ };
693
+ if (settings.render) {
694
+ render = settings.render;
695
+ }
696
+ // function to render autocomplete groups
697
+ var renderGroup = function (groupName, _) {
698
+ var groupDiv = doc.createElement('div');
699
+ groupDiv.textContent = groupName;
700
+ return groupDiv;
701
+ };
702
+ if (settings.renderGroup) {
703
+ renderGroup = settings.renderGroup;
704
+ }
705
+ var fragment = doc.createDocumentFragment();
706
+ var prevGroup = uid();
707
+ items.forEach(function (item, index) {
708
+ if (item.group && item.group !== prevGroup) {
709
+ prevGroup = item.group;
710
+ var groupDiv = renderGroup(item.group, inputValue);
711
+ if (groupDiv) {
712
+ groupDiv.className += ' group';
713
+ fragment.appendChild(groupDiv);
714
+ }
715
+ }
716
+ var div = render(item, inputValue, index);
717
+ if (div) {
718
+ div.id = container.id + "_" + index;
719
+ div.setAttribute('role', 'option');
720
+ div.addEventListener('click', function (ev) {
721
+ suppressAutocomplete = true;
722
+ try {
723
+ settings.onSelect(item, input);
724
+ }
725
+ finally {
726
+ suppressAutocomplete = false;
727
+ }
728
+ clear();
729
+ ev.preventDefault();
730
+ ev.stopPropagation();
731
+ });
732
+ if (item === selected) {
733
+ div.className += ' selected';
734
+ div.setAttribute('aria-selected', 'true');
735
+ input.setAttribute('aria-activedescendant', div.id);
736
+ }
737
+ fragment.appendChild(div);
738
+ }
739
+ });
740
+ container.appendChild(fragment);
741
+ if (items.length < 1) {
742
+ if (settings.emptyMsg) {
743
+ var empty = doc.createElement('div');
744
+ empty.id = container.id + "_" + uid();
745
+ empty.className = 'empty';
746
+ empty.textContent = settings.emptyMsg;
747
+ container.appendChild(empty);
748
+ input.setAttribute('aria-activedescendant', empty.id);
749
+ }
750
+ else {
751
+ clear();
752
+ return;
753
+ }
754
+ }
755
+ attach();
756
+ updatePosition();
757
+ updateScroll();
758
+ }
759
+ function updateIfDisplayed() {
760
+ if (containerDisplayed()) {
761
+ update();
762
+ }
763
+ }
764
+ function resizeEventHandler() {
765
+ updateIfDisplayed();
766
+ }
767
+ function scrollEventHandler(e) {
768
+ if (e.target !== container) {
769
+ updateIfDisplayed();
770
+ }
771
+ else {
772
+ e.preventDefault();
773
+ }
774
+ }
775
+ function inputEventHandler() {
776
+ if (!suppressAutocomplete) {
777
+ fetch(0 /* Keyboard */);
778
+ }
779
+ }
780
+ /**
781
+ * Automatically move scroll bar if selected item is not visible
782
+ */
783
+ function updateScroll() {
784
+ var elements = container.getElementsByClassName('selected');
785
+ if (elements.length > 0) {
786
+ var element = elements[0];
787
+ // make group visible
788
+ var previous = element.previousElementSibling;
789
+ if (previous && previous.className.indexOf('group') !== -1 && !previous.previousElementSibling) {
790
+ element = previous;
791
+ }
792
+ if (element.offsetTop < container.scrollTop) {
793
+ container.scrollTop = element.offsetTop;
794
+ }
795
+ else {
796
+ var selectBottom = element.offsetTop + element.offsetHeight;
797
+ var containerBottom = container.scrollTop + container.offsetHeight;
798
+ if (selectBottom > containerBottom) {
799
+ container.scrollTop += selectBottom - containerBottom;
800
+ }
801
+ }
802
+ }
803
+ }
804
+ function selectPreviousSuggestion() {
805
+ var index = items.indexOf(selected);
806
+ selected = index === -1
807
+ ? undefined
808
+ : items[(index + items.length - 1) % items.length];
809
+ updateSelectedSuggestion(index);
810
+ }
811
+ function selectNextSuggestion() {
812
+ var index = items.indexOf(selected);
813
+ selected = items.length < 1
814
+ ? undefined
815
+ : index === -1
816
+ ? items[0]
817
+ : items[(index + 1) % items.length];
818
+ updateSelectedSuggestion(index);
819
+ }
820
+ function updateSelectedSuggestion(index) {
821
+ if (items.length > 0) {
822
+ unselectSuggestion(index);
823
+ selectSuggestion(items.indexOf(selected));
824
+ updateScroll();
825
+ }
826
+ }
827
+ function selectSuggestion(index) {
828
+ var element = doc.getElementById(container.id + "_" + index);
829
+ if (element) {
830
+ element.classList.add('selected');
831
+ element.setAttribute('aria-selected', 'true');
832
+ input.setAttribute('aria-activedescendant', element.id);
833
+ }
834
+ }
835
+ function unselectSuggestion(index) {
836
+ var element = doc.getElementById(container.id + "_" + index);
837
+ if (element) {
838
+ element.classList.remove('selected');
839
+ element.removeAttribute('aria-selected');
840
+ input.removeAttribute('aria-activedescendant');
841
+ }
842
+ }
843
+ function handleArrowAndEscapeKeys(ev, key) {
844
+ var containerIsDisplayed = containerDisplayed();
845
+ if (key === 'Escape') {
846
+ clear();
847
+ }
848
+ else {
849
+ if (!containerIsDisplayed || items.length < 1) {
850
+ return;
851
+ }
852
+ key === 'ArrowUp'
853
+ ? selectPreviousSuggestion()
854
+ : selectNextSuggestion();
855
+ }
856
+ ev.preventDefault();
857
+ if (containerIsDisplayed) {
858
+ ev.stopPropagation();
859
+ }
860
+ }
861
+ function handleEnterKey(ev) {
862
+ if (selected) {
863
+ if (preventSubmit === 2 /* OnSelect */) {
864
+ ev.preventDefault();
865
+ }
866
+ suppressAutocomplete = true;
867
+ try {
868
+ settings.onSelect(selected, input);
869
+ }
870
+ finally {
871
+ suppressAutocomplete = false;
872
+ }
873
+ clear();
874
+ }
875
+ if (preventSubmit === 1 /* Always */) {
876
+ ev.preventDefault();
877
+ }
878
+ }
879
+ function keydownEventHandler(ev) {
880
+ var key = ev.key;
881
+ switch (key) {
882
+ case 'ArrowUp':
883
+ case 'ArrowDown':
884
+ case 'Escape':
885
+ handleArrowAndEscapeKeys(ev, key);
886
+ break;
887
+ case 'Enter':
888
+ handleEnterKey(ev);
889
+ break;
890
+ }
891
+ }
892
+ function focusEventHandler() {
893
+ if (showOnFocus) {
894
+ fetch(1 /* Focus */);
895
+ }
896
+ }
897
+ function fetch(trigger) {
898
+ if (input.value.length >= minLen || trigger === 1 /* Focus */) {
899
+ clearDebounceTimer();
900
+ debounceTimer = window.setTimeout(function () { return startFetch(input.value, trigger, input.selectionStart || 0); }, trigger === 0 /* Keyboard */ || trigger === 2 /* Mouse */ ? debounceWaitMs : 0);
901
+ }
902
+ else {
903
+ clear();
904
+ }
905
+ }
906
+ function startFetch(inputText, trigger, cursorPos) {
907
+ if (destroyed)
908
+ return;
909
+ var savedFetchCounter = ++fetchCounter;
910
+ settings.fetch(inputText, function (elements) {
911
+ if (fetchCounter === savedFetchCounter && elements) {
912
+ items = elements;
913
+ inputValue = inputText;
914
+ selected = (items.length < 1 || disableAutoSelect) ? undefined : items[0];
915
+ update();
916
+ }
917
+ }, trigger, cursorPos);
918
+ }
919
+ function keyupEventHandler(e) {
920
+ if (settings.keyup) {
921
+ settings.keyup({
922
+ event: e,
923
+ fetch: function () { return fetch(0 /* Keyboard */); }
924
+ });
925
+ return;
926
+ }
927
+ if (!containerDisplayed() && e.key === 'ArrowDown') {
928
+ fetch(0 /* Keyboard */);
929
+ }
930
+ }
931
+ function clickEventHandler(e) {
932
+ settings.click && settings.click({
933
+ event: e,
934
+ fetch: function () { return fetch(2 /* Mouse */); }
935
+ });
936
+ }
937
+ function blurEventHandler() {
938
+ // when an item is selected by mouse click, the blur event will be initiated before the click event and remove DOM elements,
939
+ // so that the click event will never be triggered. In order to avoid this issue, DOM removal should be delayed.
940
+ setTimeout(function () {
941
+ if (doc.activeElement !== input) {
942
+ clear();
943
+ }
944
+ }, 200);
945
+ }
946
+ function manualFetch() {
947
+ startFetch(input.value, 3 /* Manual */, input.selectionStart || 0);
948
+ }
949
+ /**
950
+ * Fixes #26: on long clicks focus will be lost and onSelect method will not be called
951
+ */
952
+ container.addEventListener('mousedown', function (evt) {
953
+ evt.stopPropagation();
954
+ evt.preventDefault();
955
+ });
956
+ /**
957
+ * Fixes #30: autocomplete closes when scrollbar is clicked in IE
958
+ * See: https://stackoverflow.com/a/9210267/13172349
959
+ */
960
+ container.addEventListener('focus', function () { return input.focus(); });
961
+ // If the custom autocomplete container is already appended to the DOM during widget initialization, detach it.
962
+ detach();
963
+ /**
964
+ * This function will remove DOM elements and clear event handlers
965
+ */
966
+ function destroy() {
967
+ input.removeEventListener('focus', focusEventHandler);
968
+ input.removeEventListener('keyup', keyupEventHandler);
969
+ input.removeEventListener('click', clickEventHandler);
970
+ input.removeEventListener('keydown', keydownEventHandler);
971
+ input.removeEventListener('input', inputEventHandler);
972
+ input.removeEventListener('blur', blurEventHandler);
973
+ window.removeEventListener('resize', resizeEventHandler);
974
+ doc.removeEventListener('scroll', scrollEventHandler, true);
975
+ input.removeAttribute('role');
976
+ input.removeAttribute('aria-expanded');
977
+ input.removeAttribute('aria-autocomplete');
978
+ input.removeAttribute('aria-controls');
979
+ input.removeAttribute('aria-activedescendant');
980
+ input.removeAttribute('aria-owns');
981
+ input.removeAttribute('aria-haspopup');
982
+ clearDebounceTimer();
983
+ clear();
984
+ destroyed = true;
985
+ }
986
+ // setup event handlers
987
+ input.addEventListener('keyup', keyupEventHandler);
988
+ input.addEventListener('click', clickEventHandler);
989
+ input.addEventListener('keydown', keydownEventHandler);
990
+ input.addEventListener('input', inputEventHandler);
991
+ input.addEventListener('blur', blurEventHandler);
992
+ input.addEventListener('focus', focusEventHandler);
993
+ window.addEventListener('resize', resizeEventHandler);
994
+ doc.addEventListener('scroll', scrollEventHandler, true);
995
+ return {
996
+ destroy: destroy,
997
+ fetch: manualFetch
998
+ };
999
999
  }
1000
1000
 
1001
1001
  class TagOption extends HTMLElement {