mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 06:32:12 -03:00
checkpoint
This commit is contained in:
@@ -18,10 +18,20 @@ export class SearchManager {
|
||||
this.recursiveSearchToggle = document.getElementById('recursiveSearchToggle');
|
||||
|
||||
this.searchTimeout = null;
|
||||
this.currentPage = document.body.dataset.page || 'loras';
|
||||
this.currentPage = options.page || document.body.dataset.page || 'loras';
|
||||
this.isSearching = false;
|
||||
|
||||
// Create clear button for search input
|
||||
this.createClearButton();
|
||||
|
||||
this.initEventListeners();
|
||||
this.loadSearchPreferences();
|
||||
|
||||
// Initialize panel positions
|
||||
this.updatePanelPositions();
|
||||
|
||||
// Add resize listener
|
||||
window.addEventListener('resize', this.updatePanelPositions.bind(this));
|
||||
}
|
||||
|
||||
initEventListeners() {
|
||||
@@ -30,12 +40,14 @@ export class SearchManager {
|
||||
this.searchInput.addEventListener('input', () => {
|
||||
clearTimeout(this.searchTimeout);
|
||||
this.searchTimeout = setTimeout(() => this.performSearch(), this.options.searchDelay);
|
||||
this.updateClearButtonVisibility();
|
||||
});
|
||||
|
||||
// Clear search with Escape key
|
||||
this.searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.searchInput.value = '';
|
||||
this.updateClearButtonVisibility();
|
||||
this.performSearch();
|
||||
}
|
||||
});
|
||||
@@ -44,14 +56,14 @@ export class SearchManager {
|
||||
// Search options toggle
|
||||
if (this.searchOptionsToggle) {
|
||||
this.searchOptionsToggle.addEventListener('click', () => {
|
||||
this.searchOptionsPanel.classList.toggle('hidden');
|
||||
this.toggleSearchOptionsPanel();
|
||||
});
|
||||
}
|
||||
|
||||
// Close search options
|
||||
if (this.closeSearchOptions) {
|
||||
this.closeSearchOptions.addEventListener('click', () => {
|
||||
this.searchOptionsPanel.classList.add('hidden');
|
||||
this.closeSearchOptionsPanel();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,6 +71,16 @@ export class SearchManager {
|
||||
if (this.searchOptionTags) {
|
||||
this.searchOptionTags.forEach(tag => {
|
||||
tag.addEventListener('click', () => {
|
||||
// Check if clicking would deselect the last active option
|
||||
const activeOptions = document.querySelectorAll('.search-option-tag.active');
|
||||
if (activeOptions.length === 1 && activeOptions[0] === tag) {
|
||||
// Don't allow deselecting the last option
|
||||
if (typeof showToast === 'function') {
|
||||
showToast('At least one search option must be selected', 'info');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tag.classList.toggle('active');
|
||||
this.saveSearchPreferences();
|
||||
this.performSearch();
|
||||
@@ -73,6 +95,89 @@ export class SearchManager {
|
||||
this.performSearch();
|
||||
});
|
||||
}
|
||||
|
||||
// Add global click handler to close panels when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
// Close search options panel when clicking outside
|
||||
if (this.searchOptionsPanel &&
|
||||
!this.searchOptionsPanel.contains(e.target) &&
|
||||
e.target !== this.searchOptionsToggle &&
|
||||
!this.searchOptionsToggle.contains(e.target)) {
|
||||
this.closeSearchOptionsPanel();
|
||||
}
|
||||
|
||||
// Close filter panel when clicking outside (if filterManager exists)
|
||||
const filterPanel = document.getElementById('filterPanel');
|
||||
const filterButton = document.getElementById('filterButton');
|
||||
if (filterPanel &&
|
||||
!filterPanel.contains(e.target) &&
|
||||
e.target !== filterButton &&
|
||||
!filterButton.contains(e.target) &&
|
||||
window.filterManager) {
|
||||
window.filterManager.closeFilterPanel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createClearButton() {
|
||||
// Create clear button if it doesn't exist
|
||||
if (!this.searchInput) return;
|
||||
|
||||
// Check if clear button already exists
|
||||
let clearButton = this.searchInput.parentNode.querySelector('.search-clear');
|
||||
|
||||
if (!clearButton) {
|
||||
// Create clear button
|
||||
clearButton = document.createElement('button');
|
||||
clearButton.className = 'search-clear';
|
||||
clearButton.innerHTML = '<i class="fas fa-times"></i>';
|
||||
clearButton.title = 'Clear search';
|
||||
|
||||
// Add click handler
|
||||
clearButton.addEventListener('click', () => {
|
||||
this.searchInput.value = '';
|
||||
this.updateClearButtonVisibility();
|
||||
this.performSearch();
|
||||
});
|
||||
|
||||
// Insert after search input
|
||||
this.searchInput.parentNode.appendChild(clearButton);
|
||||
}
|
||||
|
||||
this.clearButton = clearButton;
|
||||
|
||||
// Set initial visibility
|
||||
this.updateClearButtonVisibility();
|
||||
}
|
||||
|
||||
updateClearButtonVisibility() {
|
||||
if (this.clearButton) {
|
||||
this.clearButton.classList.toggle('visible', this.searchInput.value.length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
toggleSearchOptionsPanel() {
|
||||
if (this.searchOptionsPanel) {
|
||||
const isHidden = this.searchOptionsPanel.classList.contains('hidden');
|
||||
if (isHidden) {
|
||||
// Update position before showing
|
||||
this.updatePanelPositions();
|
||||
this.searchOptionsPanel.classList.remove('hidden');
|
||||
this.searchOptionsToggle.classList.add('active');
|
||||
|
||||
// Ensure the panel is visible
|
||||
this.searchOptionsPanel.style.display = 'block';
|
||||
} else {
|
||||
this.closeSearchOptionsPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeSearchOptionsPanel() {
|
||||
if (this.searchOptionsPanel) {
|
||||
this.searchOptionsPanel.classList.add('hidden');
|
||||
this.searchOptionsToggle.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
loadSearchPreferences() {
|
||||
@@ -93,11 +198,45 @@ export class SearchManager {
|
||||
if (this.recursiveSearchToggle && preferences.recursive !== undefined) {
|
||||
this.recursiveSearchToggle.checked = preferences.recursive;
|
||||
}
|
||||
|
||||
// Ensure at least one search option is selected
|
||||
this.validateSearchOptions();
|
||||
} catch (error) {
|
||||
console.error('Error loading search preferences:', error);
|
||||
// Set default options if loading fails
|
||||
this.setDefaultSearchOptions();
|
||||
}
|
||||
}
|
||||
|
||||
validateSearchOptions() {
|
||||
// Check if at least one search option is active
|
||||
const hasActiveOption = Array.from(this.searchOptionTags).some(tag =>
|
||||
tag.classList.contains('active')
|
||||
);
|
||||
|
||||
// If no search options are active, activate default options
|
||||
if (!hasActiveOption) {
|
||||
this.setDefaultSearchOptions();
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultSearchOptions() {
|
||||
// Default to filename search option if available
|
||||
const filenameOption = Array.from(this.searchOptionTags).find(tag =>
|
||||
tag.dataset.option === 'filename'
|
||||
);
|
||||
|
||||
if (filenameOption) {
|
||||
filenameOption.classList.add('active');
|
||||
} else if (this.searchOptionTags.length > 0) {
|
||||
// Otherwise, select the first option
|
||||
this.searchOptionTags[0].classList.add('active');
|
||||
}
|
||||
|
||||
// Save the default preferences
|
||||
this.saveSearchPreferences();
|
||||
}
|
||||
|
||||
saveSearchPreferences() {
|
||||
try {
|
||||
const options = {};
|
||||
@@ -117,15 +256,63 @@ export class SearchManager {
|
||||
}
|
||||
|
||||
getActiveSearchOptions() {
|
||||
const options = [];
|
||||
const options = {};
|
||||
this.searchOptionTags.forEach(tag => {
|
||||
if (tag.classList.contains('active')) {
|
||||
options.push(tag.dataset.option);
|
||||
}
|
||||
options[tag.dataset.option] = tag.classList.contains('active');
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
updatePanelPositions() {
|
||||
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
|
||||
const filterPanel = document.getElementById('filterPanel');
|
||||
|
||||
if (!searchOptionsPanel && !filterPanel) return;
|
||||
|
||||
// Get the header element
|
||||
const header = document.querySelector('.app-header');
|
||||
if (!header) return;
|
||||
|
||||
// Calculate the position based on the bottom of the header
|
||||
const headerRect = header.getBoundingClientRect();
|
||||
const topPosition = headerRect.bottom + 5; // Add 5px padding
|
||||
|
||||
// Set the positions
|
||||
if (searchOptionsPanel) {
|
||||
searchOptionsPanel.style.top = `${topPosition}px`;
|
||||
|
||||
// Make sure the panel is visible when positioned
|
||||
if (!searchOptionsPanel.classList.contains('hidden') &&
|
||||
window.getComputedStyle(searchOptionsPanel).display === 'none') {
|
||||
searchOptionsPanel.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
if (filterPanel) {
|
||||
filterPanel.style.top = `${topPosition}px`;
|
||||
}
|
||||
|
||||
// Adjust panel horizontal position based on the search container
|
||||
const searchContainer = document.querySelector('.header-search');
|
||||
if (searchContainer) {
|
||||
const searchRect = searchContainer.getBoundingClientRect();
|
||||
|
||||
// Position the search options panel aligned with the search container
|
||||
if (searchOptionsPanel) {
|
||||
searchOptionsPanel.style.right = `${window.innerWidth - searchRect.right}px`;
|
||||
}
|
||||
|
||||
// Position the filter panel aligned with the filter button
|
||||
if (filterPanel) {
|
||||
const filterButton = document.getElementById('filterButton');
|
||||
if (filterButton) {
|
||||
const filterRect = filterButton.getBoundingClientRect();
|
||||
filterPanel.style.right = `${window.innerWidth - filterRect.right}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
performSearch() {
|
||||
const query = this.searchInput.value.trim();
|
||||
const options = this.getActiveSearchOptions();
|
||||
|
||||
Reference in New Issue
Block a user