pro-suggest.js 7.5 KB

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