pro-suggest.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // pro suggest functionality
  2. (function() {
  3. let suggestionsOuter = null;
  4. const debounce = (func, wait) => {
  5. let timeout;
  6. return function executedFunction(...args) {
  7. const later = () => {
  8. clearTimeout(timeout);
  9. func(...args);
  10. };
  11. clearTimeout(timeout);
  12. timeout = setTimeout(later, wait);
  13. };
  14. };
  15. var lastTerm = '';
  16. var returnedFunction = debounce(function (elem) {
  17. var term = elem.val();
  18. if (!!term && lastTerm !== term) {
  19. $.get('/pro-suggest?term=' + $.trim(term) + '&type=' + elem.attr('provider-type'), function (_data) {
  20. suggestionsOuter.html(_data).removeClass('d-none');
  21. });
  22. lastTerm = term;
  23. } else {
  24. suggestionsOuter.addClass('d-none');
  25. }
  26. }, 250);
  27. function handleKeydown(elem, e) {
  28. let term = $.trim(elem.val());
  29. let activeItem = suggestionsOuter.find('.suggest-item.active');
  30. switch (e.which) {
  31. case 27:
  32. suggestionsOuter.addClass('d-none');
  33. markEventAsConsumed(e);
  34. return false;
  35. case 38:
  36. if (activeItem.prev().length) {
  37. activeItem.prev()
  38. .addClass('active')
  39. .siblings().removeClass('active');
  40. activeItem = suggestionsOuter.find('.suggest-item.active');
  41. if (activeItem.length) {
  42. activeItem[0].scrollIntoView();
  43. }
  44. }
  45. return false;
  46. case 40:
  47. if (activeItem.next().length) {
  48. activeItem.next()
  49. .addClass('active')
  50. .siblings().removeClass('active');
  51. activeItem = suggestionsOuter.find('.suggest-item.active');
  52. if (activeItem.length) {
  53. activeItem[0].scrollIntoView();
  54. }
  55. }
  56. return false;
  57. case 13:
  58. if (activeItem.length) {
  59. activeItem.first().click();
  60. }
  61. return false;
  62. default:
  63. if (!!term) {
  64. suggestionsOuter
  65. .html('<span class="d-block no-suggest-items">Searching...</span>')
  66. .removeClass('d-none');
  67. returnedFunction(elem);
  68. } else {
  69. suggestionsOuter.addClass('d-none');
  70. }
  71. break;
  72. }
  73. }
  74. function handleKeypress(elem, e) {
  75. var term = $.trim(elem.val());
  76. if (!!term) {
  77. suggestionsOuter
  78. .html('<span class="d-block no-suggest-items">Searching...</span>')
  79. .removeClass('d-none');
  80. returnedFunction(elem);
  81. } else {
  82. suggestionsOuter.addClass('d-none');
  83. }
  84. }
  85. window.initProSuggest = function() {
  86. // make select[provider-search] hidden & insert a textbox with pro-suggest
  87. $('select[provider-search]:not([pro-suggest-initialized]):not([no-auto-pro-suggest-init])').each(function() {
  88. let elem = $(this);
  89. elem.next('.pro-suggest-input').remove();
  90. elem.next('.pro-suggestions-container').remove();
  91. let input = $('<input type="text" placeholder="Pro">').addClass('pro-suggest-input form-control form-control-sm').insertAfter(elem);
  92. input.attr('provider-type', elem.attr('provider-type'));
  93. $('<div class="pro-suggestions-container position-relative">' +
  94. '<div class="suggestions-outer pro-suggestions position-absolute d-none"></div>' +
  95. '</div>').insertAfter(input);
  96. elem.hide();
  97. let proUid = elem.attr('data-pro-uid');
  98. if(!!proUid) {
  99. $.get('/pro-display-name/' + proUid, function(_data) {
  100. input.val(_data).data('original', _data);
  101. elem.empty().append($('<option value="' + proUid + '" selected/>').text(_data));
  102. });
  103. }
  104. else {
  105. input.val(elem.attr('data-pro-name')).data('original', elem.attr('data-pro-name'));
  106. }
  107. if(elem.is('[required]')) {
  108. input.attr('required', 'required');
  109. }
  110. input
  111. .off('keydown.pro-suggest')
  112. .on('keydown.pro-suggest', function (e) {
  113. suggestionsOuter = $(this).next('.pro-suggestions-container').find('>.suggestions-outer');
  114. return handleKeydown($(this), e);
  115. })
  116. .off('keypress.pro-suggest')
  117. .on('keypress.pro-suggest', function (e) {
  118. suggestionsOuter = $(this).next('.pro-suggestions-container').find('>.suggestions-outer');
  119. return handleKeypress($(this), e);
  120. });
  121. // .off('blur.pro-suggest')
  122. // .on('blur.pro-suggest', function (e) {
  123. // window.setTimeout(() => {
  124. // $(this).next('.pro-suggestions-container').find('>.suggestions-outer').addClass('d-none');
  125. // $(this).val($(this).data('original'));
  126. // }, 50);
  127. // });
  128. $(this).attr('pro-suggest-initialized', 1);
  129. });
  130. $(document).off('click', '.suggest-item.pro-suggest[data-target-uid]');
  131. $(document).on('click', '.suggest-item.pro-suggest[data-target-uid]', function () {
  132. $('.suggestions-outer.pro-suggestions').addClass('d-none');
  133. let uid = $(this).attr('data-target-uid'),
  134. label = $.trim($(this).text());
  135. // set select value
  136. let select = $(this).closest('.position-relative')
  137. .prev('.pro-suggest-input')
  138. .prev('select[provider-search]');
  139. select.empty().append($('<option value="' + uid + '" selected/>').text(label));
  140. select.val(uid).trigger('change');
  141. select.trigger('pro-changed');
  142. // set input value
  143. $(this).closest('.position-relative')
  144. .prev('.pro-suggest-input')
  145. .val(label)
  146. .data('original', label)
  147. .trigger('change');
  148. return false;
  149. });
  150. }
  151. addMCInitializer('pro-suggest', initProSuggest);
  152. })();