search-bar.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // 搜索栏模块(复制自 client/js/disk/search-bar.js)
  2. class ResourceManagerSearchBar {
  3. constructor(options = {}) {
  4. this.input = options.input;
  5. this.clearButton = options.clearButton;
  6. this.fileList = options.fileList;
  7. this.emptyState = options.emptyState;
  8. this.getResources = options.getResources || (() => []);
  9. this.renderAll = options.renderAll || (() => {});
  10. this.createFileItem = options.createFileItem || (() => null);
  11. this.noResultMessage = options.noResultMessage || '没有找到匹配的文件';
  12. this.isSearching = false;
  13. this.init();
  14. }
  15. init() {
  16. if (!this.input) return;
  17. this.input.addEventListener('input', () => this.handleSearch());
  18. this.input.addEventListener('keydown', (e) => {
  19. if (e.key === 'Escape') {
  20. this.clear();
  21. }
  22. });
  23. if (this.clearButton) {
  24. this.clearButton.addEventListener('click', () => this.clear());
  25. }
  26. }
  27. async handleSearch() {
  28. const keyword = this.input.value.trim().toLowerCase();
  29. if (!keyword) {
  30. this.clear({ noRender: false });
  31. return;
  32. }
  33. this.isSearching = true;
  34. this.showClearButton();
  35. // 获取资源列表(可能是异步的)
  36. let resources = this.getResources();
  37. if (resources instanceof Promise) {
  38. resources = await resources;
  39. }
  40. // 过滤匹配的资源
  41. const filtered = resources.filter(resource => {
  42. const name = (resource.name || '').toLowerCase();
  43. return name.includes(keyword);
  44. });
  45. this.renderSearchResults(filtered);
  46. }
  47. renderSearchResults(resources) {
  48. if (!this.fileList) return;
  49. this.fileList.innerHTML = '';
  50. if (resources.length === 0) {
  51. if (this.emptyState) {
  52. this.emptyState.classList.add('show');
  53. const p = this.emptyState.querySelector('p');
  54. if (p) p.textContent = this.noResultMessage;
  55. }
  56. return;
  57. }
  58. if (this.emptyState) {
  59. this.emptyState.classList.remove('show');
  60. }
  61. resources.forEach(resource => {
  62. const item = this.createFileItem(resource);
  63. if (item) {
  64. this.fileList.appendChild(item);
  65. }
  66. });
  67. }
  68. clear(options = {}) {
  69. const { noRender = false } = options;
  70. this.input.value = '';
  71. this.isSearching = false;
  72. this.hideClearButton();
  73. if (!noRender) {
  74. this.renderAll();
  75. }
  76. }
  77. showClearButton() {
  78. if (this.clearButton) {
  79. this.clearButton.style.display = 'flex';
  80. }
  81. }
  82. hideClearButton() {
  83. if (this.clearButton) {
  84. this.clearButton.style.display = 'none';
  85. }
  86. }
  87. }