search.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. function customSearch() {
  2. let searchableContent = document.querySelectorAll('tr td:not(:last-of-type)');
  3. let searchInput = document.querySelector('input[type="search"]');
  4. let searchResults = document.querySelector('#search_results');
  5. let isResultOpen = false;
  6. let resultAmount = 0;
  7. let resultAmountText = document.querySelector('#result_amount');
  8. let hilightedWords;
  9. let typingTimer;
  10. let currentSelectedWord = 0;
  11. let downArrow = document.querySelector('#search_results div div img:first-of-type');
  12. let upArrow = document.querySelector('#search_results div div img:last-of-type');
  13. let thereAreResults = false;
  14. let inputIsActive = false;
  15. searchInput.addEventListener('focus', () => { inputIsActive = true; toggleSearchResults(); });
  16. searchInput.addEventListener('blur', () => { inputIsActive = false; });
  17. searchInput.addEventListener('keydown', function(e) {
  18. if ((e.key === 'Enter' || e.keyCode === 13) && resultAmount > 1) {
  19. if (+resultAmountText.innerText.split('/')[0] === resultAmount) {
  20. getToFirstOccurence();
  21. } else {
  22. getToNextOccurence(downArrow);
  23. }
  24. } else {
  25. triggerSearch();
  26. }
  27. });
  28. function triggerSearch() {
  29. setTimeout(() => {
  30. hilightedWords = [];
  31. resultAmount = 0;
  32. removeHighlightTags();
  33. let input = searchInput.value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
  34. if (searchInput.value.length >= 3) {
  35. thereAreResults = true;
  36. clearTimeout(typingTimer);
  37. typingTimer = setTimeout(function() {
  38. searchInContent(input);
  39. let currentScroll = window.scrollY;
  40. if (hilightedWords.length != 0) {
  41. searchResults.querySelector('div p:first-of-type').style.display = "block";
  42. searchResults.querySelector('div p:last-of-type').style.display = "none";
  43. for (let i = 0; i < hilightedWords.length; i++) {
  44. let wordBoundingTop = hilightedWords[i].getBoundingClientRect().top;
  45. if (hilightedWords.length <= 1) {
  46. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  47. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  48. currentSelectedWord = 1;
  49. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText;
  50. upArrow.classList.add('disabled');
  51. downArrow.classList.add('disabled');
  52. } else {
  53. if (currentScroll <= wordBoundingTop + currentScroll && i === 0) {
  54. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  55. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  56. currentSelectedWord = 1;
  57. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText;
  58. upArrow.classList.add('disabled');
  59. downArrow.classList.remove('disabled');
  60. break;
  61. } else if (
  62. currentScroll <= wordBoundingTop + currentScroll && currentScroll >= hilightedWords[i - 1]?.getBoundingClientRect().top + currentScroll
  63. ) {
  64. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  65. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  66. currentSelectedWord = i + 1;
  67. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText;
  68. upArrow.classList.remove('disabled');
  69. if (i === hilightedWords.length - 1) {
  70. downArrow.classList.add('disabled');
  71. } else {
  72. downArrow.classList.remove('disabled');
  73. }
  74. break;
  75. } else if (currentScroll >= wordBoundingTop && i === hilightedWords.length - 1) {
  76. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  77. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  78. currentSelectedWord = hilightedWords.length;
  79. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText;
  80. upArrow.classList.remove('disabled');
  81. downArrow.classList.add('disabled');
  82. break;
  83. }
  84. }
  85. }
  86. } else {
  87. searchResults.querySelector('div p:first-of-type').style.display = "none";
  88. searchResults.querySelector('div p:last-of-type').style.display = "block";
  89. upArrow.classList.add('disabled');
  90. downArrow.classList.add('disabled');
  91. }
  92. }, 800);
  93. } else {
  94. removeHighlightTags();
  95. clearTimeout(typingTimer);
  96. thereAreResults = false;
  97. searchResults.querySelector('div p:first-of-type').style.display = "none";
  98. searchResults.querySelector('div p:last-of-type').style.display = "block";
  99. upArrow.classList.add('disabled');
  100. downArrow.classList.add('disabled');
  101. }
  102. }, 10);
  103. }
  104. function searchInContent(input) {
  105. for (let content of searchableContent) {
  106. if (content.innerText != '') {
  107. if (content.children.length > 0) {
  108. for (let textEl of content.children) {
  109. compareTexts(textEl, input);
  110. }
  111. } else {
  112. compareTexts(content, input);
  113. }
  114. }
  115. }
  116. resultAmountText.innerText = resultAmount;
  117. }
  118. function compareTexts(textEl, input) {
  119. if (textEl.innerText !== '') {
  120. if (textEl.parentElement.tagName === "TR") {
  121. input = input.replace(/'/g, '’');
  122. }
  123. if (textEl.innerHTML.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").includes(input)) {
  124. let splitContent = textEl.innerHTML.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").split(input);
  125. let processedText = '';
  126. for (let i = 0; i < splitContent.length; i++) {
  127. if (splitContent[0] !== '' || splitContent[splitContent.length - 1] !== '') {
  128. if (i === 0) {
  129. processedText += textEl.innerHTML.substring(0, splitContent[i].length);
  130. } else {
  131. let amountOfTextToConcatenate = 0;
  132. for (let j = 0; j <= i - 1; j ++) {
  133. amountOfTextToConcatenate += splitContent[j].length + input.length;
  134. }
  135. processedText +=
  136. '<span class="highlight">' +
  137. textEl.innerHTML.substring(amountOfTextToConcatenate - input.length, amountOfTextToConcatenate) +
  138. '</span>' +
  139. textEl.innerHTML.substring(
  140. amountOfTextToConcatenate, amountOfTextToConcatenate + splitContent[i].length
  141. );
  142. }
  143. } else if (splitContent[splitContent.length - 1] === '' && splitContent[0] === '') {
  144. processedText = '<span class="highlight">' + textEl.innerHTML + '</span>';
  145. }
  146. }
  147. textEl.innerHTML = processedText;
  148. hilightedWords = document.querySelectorAll('.highlight');
  149. resultAmount = hilightedWords.length;
  150. }
  151. }
  152. }
  153. function removeHighlightTags() {
  154. for (let content of searchableContent) {
  155. if (content.innerHTML.includes('<span class="highlight">')) {
  156. content.innerHTML = content.innerHTML.replace(/<span class="highlight">|<\/span>/g, '');
  157. }
  158. }
  159. }
  160. function toggleSearchResults() {
  161. // dans le if thereAreResults || inputIsActive
  162. // si on veut que les résultats restent ouvert
  163. // quand il y a des résultats
  164. if (inputIsActive) {
  165. searchResults.style.top = `${searchInput.getBoundingClientRect().bottom + 5}px`;
  166. searchResults.style.display = "block";
  167. searchResults.style.opacity = 1;
  168. searchResults.style.maxHeight = "1000px";
  169. isResultOpen = true;
  170. } else {
  171. searchResults.style.opacity = 0;
  172. searchResults.style.maxHeight = "0px";
  173. isResultOpen = false;
  174. setTimeout(() => {
  175. searchResults.style.display = "none";
  176. }, 300);
  177. }
  178. }
  179. upArrow.addEventListener('click', function (el) {
  180. getToPrevOccurence(el)
  181. });
  182. function getToPrevOccurence(el) {
  183. if (!el.target.classList.contains('disabled')) {
  184. let currentScroll = window.scrollY;
  185. currentSelectedWord--;
  186. let wordBoundingTop = hilightedWords[currentSelectedWord - 1].getBoundingClientRect().top;
  187. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  188. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  189. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText.split('/')[1];
  190. if (currentSelectedWord === 1) {
  191. upArrow.classList.add('disabled');
  192. downArrow.classList.remove('disabled');
  193. } else {
  194. upArrow.classList.remove('disabled');
  195. downArrow.classList.remove('disabled');
  196. }
  197. }
  198. }
  199. downArrow.addEventListener('click', function (el) {
  200. getToNextOccurence(el.target);
  201. });
  202. function getToNextOccurence(el) {
  203. if (!el.classList.contains('disabled')) {
  204. let currentScroll = window.scrollY;
  205. currentSelectedWord++;
  206. let wordBoundingTop = hilightedWords[currentSelectedWord - 1].getBoundingClientRect().top;
  207. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  208. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  209. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText.split('/')[1];
  210. if (currentSelectedWord === hilightedWords.length) {
  211. downArrow.classList.add('disabled');
  212. upArrow.classList.remove('disabled');
  213. } else {
  214. downArrow.classList.remove('disabled');
  215. upArrow.classList.remove('disabled');
  216. }
  217. }
  218. }
  219. function getToFirstOccurence() {
  220. let currentScroll = window.scrollY;
  221. currentSelectedWord = 1;
  222. let wordBoundingTop = hilightedWords[currentSelectedWord - 1].getBoundingClientRect().top;
  223. let scrollValue = (wordBoundingTop + currentScroll) - window.innerHeight / 2;
  224. window.scrollTo({ top: scrollValue, behavior: 'smooth' });
  225. resultAmountText.innerText = currentSelectedWord + "/" + resultAmountText.innerText.split('/')[1];
  226. downArrow.classList.remove('disabled');
  227. upArrow.classList.add('disabled');
  228. }
  229. let tagsDiv = document.querySelector('#search_results > div:last-of-type');
  230. window.addEventListener('click', function (el) {
  231. if (!searchResults.contains(el.target) && isResultOpen && el.target != searchInput && el.target != tagsDiv) {
  232. toggleSearchResults();
  233. }
  234. });
  235. let searchWordList = document.querySelector('#content_search_tag');
  236. searchWordList = searchWordList.innerText.substring(1, searchWordList.innerText.length - 1).split(', ');
  237. for (let tag of searchWordList) {
  238. let tagWrapper = document.createElement('p');
  239. tagWrapper.innerText = tag;
  240. tagWrapper.addEventListener('click', function () {
  241. searchInput.value = tag;
  242. triggerSearch();
  243. });
  244. tagsDiv.appendChild(tagWrapper);
  245. }
  246. }
  247. export { customSearch };