search.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. const contentContainer = document.querySelector( '#page-content' );
  2. const searchContainer = document.querySelector( '#search-content' );
  3. const resultBox = document.querySelector( '#search-result' );
  4. // eslint-disable-next-line no-unused-vars
  5. function hideSearch() {
  6. searchContainer.style.display = 'none';
  7. contentContainer.style.display = 'block';
  8. }
  9. function showResultText( text ) {
  10. resultBox.innerHTML = text;
  11. }
  12. function showSearch() {
  13. searchContainer.style.display = 'block';
  14. contentContainer.style.display = 'none';
  15. }
  16. function extractUrlBase( url ) {
  17. const index = url.lastIndexOf( '/' );
  18. if ( index === - 1 ) return './';
  19. return url.slice( 0, index + 1 );
  20. }
  21. async function fetchAllData() {
  22. const { origin, pathname } = location;
  23. const baseURL = extractUrlBase( pathname );
  24. const base = origin + baseURL;
  25. const url = new URL( 'data/search.json', base );
  26. const result = await fetch( url );
  27. const { list } = await result.json();
  28. return list;
  29. }
  30. function buildSearchResult( result ) {
  31. let output = '';
  32. const removeHTMLTagsRegExp = /(<([^>]+)>)/ig;
  33. for ( const res of result ) {
  34. const { title = '', description = '' } = res.item;
  35. const _link = res.item.link.replace( '<a href="', '' ).replace( /">.*/, '' );
  36. const _title = title.replace( removeHTMLTagsRegExp, '' );
  37. const _description = description.replace( removeHTMLTagsRegExp, '' );
  38. output += `
  39. <a href="${_link}" class="search-result-item">
  40. <span class="search-result-item-title">${_title}</span>
  41. <span class="search-result-item-description">- ${_description || 'No description available.'}</span>
  42. </a>
  43. `;
  44. }
  45. return output;
  46. }
  47. function getSearchResult( list, keys, searchKey ) {
  48. const defaultOptions = {
  49. shouldSort: true,
  50. threshold: 0.4,
  51. location: 0,
  52. distance: 100,
  53. maxPatternLength: 32,
  54. minMatchCharLength: 1,
  55. keys: keys
  56. };
  57. const options = { ...defaultOptions };
  58. // eslint-disable-next-line no-undef
  59. const searchIndex = Fuse.createIndex( options.keys, list );
  60. // eslint-disable-next-line no-undef
  61. const fuse = new Fuse( list, options, searchIndex );
  62. const result = fuse.search( searchKey );
  63. if ( result.length > 20 ) {
  64. return result.slice( 0, 20 );
  65. }
  66. return result;
  67. }
  68. let searchData;
  69. // eslint-disable-next-line no-unused-vars
  70. async function search( value ) {
  71. if ( value === '' ) {
  72. hideSearch();
  73. return;
  74. }
  75. showSearch();
  76. const keys = [ 'title', 'description' ];
  77. if ( searchData === undefined ) {
  78. showResultText( 'Loading...' );
  79. try {
  80. searchData = await fetchAllData();
  81. } catch ( e ) {
  82. console.log( e );
  83. showResultText( 'Failed to load result.' );
  84. return;
  85. }
  86. }
  87. const result = getSearchResult( searchData, keys, value );
  88. if ( ! result.length ) {
  89. showResultText( 'No result found! Try some different combination.' );
  90. return;
  91. }
  92. resultBox.innerHTML = buildSearchResult( result );
  93. }
粤ICP备19079148号