mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 06:32:12 -03:00
Refactor LoraModal and RecipeSearchManager for improved functionality and performance
- Updated LoraModal to enhance lazy loading and scroll behavior, utilizing MutationObserver for dynamic content changes and adding a new helper function for the back-to-top button. - Modified RecipeSearchManager to ensure proper recipe loading through the window.recipeManager object, improving reliability in recipe reloading. - Added additional components to loras.html for better modularity and organization of the modal structure.
This commit is contained in:
@@ -706,9 +706,10 @@ function initLazyLoading(container) {
|
||||
}
|
||||
|
||||
export function setupShowcaseScroll() {
|
||||
// Change from modal-content to window/document level
|
||||
// Add event listener to document for wheel events
|
||||
document.addEventListener('wheel', (event) => {
|
||||
const modalContent = document.querySelector('.modal-content');
|
||||
// Find the active modal content
|
||||
const modalContent = document.querySelector('#loraModal .modal-content');
|
||||
if (!modalContent) return;
|
||||
|
||||
const showcase = modalContent.querySelector('.showcase-section');
|
||||
@@ -725,24 +726,52 @@ export function setupShowcaseScroll() {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}, { passive: false }); // Add passive: false option here
|
||||
}, { passive: false });
|
||||
|
||||
// Keep the existing scroll tracking code
|
||||
const modalContent = document.querySelector('.modal-content');
|
||||
if (modalContent) {
|
||||
modalContent.addEventListener('scroll', () => {
|
||||
const backToTopBtn = modalContent.querySelector('.back-to-top');
|
||||
if (backToTopBtn) {
|
||||
if (modalContent.scrollTop > 300) {
|
||||
backToTopBtn.classList.add('visible');
|
||||
} else {
|
||||
backToTopBtn.classList.remove('visible');
|
||||
// Use MutationObserver instead of deprecated DOMNodeInserted
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === 'childList' && mutation.addedNodes.length) {
|
||||
// Check if loraModal content was added
|
||||
const loraModal = document.getElementById('loraModal');
|
||||
if (loraModal && loraModal.querySelector('.modal-content')) {
|
||||
setupBackToTopButton(loraModal.querySelector('.modal-content'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Start observing the document body for changes
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
// Also try to set up the button immediately in case the modal is already open
|
||||
const modalContent = document.querySelector('#loraModal .modal-content');
|
||||
if (modalContent) {
|
||||
setupBackToTopButton(modalContent);
|
||||
}
|
||||
}
|
||||
|
||||
// New helper function to set up the back to top button
|
||||
function setupBackToTopButton(modalContent) {
|
||||
// Remove any existing scroll listeners to avoid duplicates
|
||||
modalContent.onscroll = null;
|
||||
|
||||
// Add new scroll listener
|
||||
modalContent.addEventListener('scroll', () => {
|
||||
const backToTopBtn = modalContent.querySelector('.back-to-top');
|
||||
if (backToTopBtn) {
|
||||
if (modalContent.scrollTop > 300) {
|
||||
backToTopBtn.classList.add('visible');
|
||||
} else {
|
||||
backToTopBtn.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger a scroll event to check initial position
|
||||
modalContent.dispatchEvent(new Event('scroll'));
|
||||
}
|
||||
|
||||
export function scrollToTop(button) {
|
||||
const modalContent = button.closest('.modal-content');
|
||||
if (modalContent) {
|
||||
|
||||
@@ -111,13 +111,11 @@ export class RecipeSearchManager extends SearchManager {
|
||||
}
|
||||
|
||||
resetAndReloadRecipes() {
|
||||
// This function would be implemented in the recipes page
|
||||
// Similar to resetAndReload for loras
|
||||
if (typeof window.loadRecipes === 'function') {
|
||||
window.loadRecipes();
|
||||
if (window.recipeManager && typeof window.recipeManager.loadRecipes === 'function') {
|
||||
window.recipeManager.loadRecipes();
|
||||
} else {
|
||||
// Fallback to reloading the page
|
||||
window.location.reload();
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
114
templates/components/lora_modals.html
Normal file
114
templates/components/lora_modals.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<!-- Model details Modal -->
|
||||
<div id="loraModal" class="modal"></div>
|
||||
|
||||
<!-- Download from URL Modal -->
|
||||
<div id="downloadModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<button class="close" onclick="modalManager.closeModal('downloadModal')">×</button>
|
||||
<h2>Download LoRA from URL</h2>
|
||||
|
||||
<!-- Step 1: URL Input -->
|
||||
<div class="download-step" id="urlStep">
|
||||
<div class="input-group">
|
||||
<label for="loraUrl">Civitai URL:</label>
|
||||
<input type="text" id="loraUrl" placeholder="https://civitai.com/models/..." />
|
||||
<div class="error-message" id="urlError"></div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="primary-btn" onclick="downloadManager.validateAndFetchVersions()">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Version Selection -->
|
||||
<div class="download-step" id="versionStep" style="display: none;">
|
||||
<div class="version-list" id="versionList">
|
||||
<!-- Versions will be inserted here dynamically -->
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="secondary-btn" onclick="downloadManager.backToUrl()">Back</button>
|
||||
<button class="primary-btn" onclick="downloadManager.proceedToLocation()">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Location Selection -->
|
||||
<div class="download-step" id="locationStep" style="display: none;">
|
||||
<div class="location-selection">
|
||||
<!-- Move path preview to top -->
|
||||
<div class="path-preview">
|
||||
<label>Download Location Preview:</label>
|
||||
<div class="path-display" id="targetPathDisplay">
|
||||
<span class="path-text">Select a LoRA root directory</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Select LoRA Root:</label>
|
||||
<select id="loraRoot"></select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Target Folder:</label>
|
||||
<div class="folder-browser" id="folderBrowser">
|
||||
{% for folder in folders %}
|
||||
{% if folder %}
|
||||
<div class="folder-item" data-folder="{{ folder }}">
|
||||
{{ folder }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="newFolder">New Folder (optional):</label>
|
||||
<input type="text" id="newFolder" placeholder="Enter folder name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="secondary-btn" onclick="downloadManager.backToVersions()">Back</button>
|
||||
<button class="primary-btn" onclick="downloadManager.startDownload()">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Move Model Modal -->
|
||||
<div id="moveModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="moveModalTitle">Move Model</h2>
|
||||
<span class="close" onclick="modalManager.closeModal('moveModal')">×</span>
|
||||
</div>
|
||||
<div class="location-selection">
|
||||
<div class="path-preview">
|
||||
<label>Target Location Preview:</label>
|
||||
<div class="path-display" id="moveTargetPathDisplay">
|
||||
<span class="path-text">Select a LoRA root directory</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Select LoRA Root:</label>
|
||||
<select id="moveLoraRoot"></select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Target Folder:</label>
|
||||
<div class="folder-browser" id="moveFolderBrowser">
|
||||
{% for folder in folders %}
|
||||
{% if folder %}
|
||||
<div class="folder-item" data-folder="{{ folder }}">
|
||||
{{ folder }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="moveNewFolder">New Folder (optional):</label>
|
||||
<input type="text" id="moveNewFolder" placeholder="Enter folder name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="cancel-btn" onclick="modalManager.closeModal('moveModal')">Cancel</button>
|
||||
<button class="primary-btn" onclick="moveManager.moveModel()">Move</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,6 +1,3 @@
|
||||
<!-- Model details Modal -->
|
||||
<div id="loraModal" class="modal"></div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div id="deleteModal" class="modal delete-modal">
|
||||
<div class="modal-content delete-modal-content">
|
||||
@@ -14,118 +11,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download from URL Modal -->
|
||||
<div id="downloadModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<button class="close" onclick="modalManager.closeModal('downloadModal')">×</button>
|
||||
<h2>Download LoRA from URL</h2>
|
||||
|
||||
<!-- Step 1: URL Input -->
|
||||
<div class="download-step" id="urlStep">
|
||||
<div class="input-group">
|
||||
<label for="loraUrl">Civitai URL:</label>
|
||||
<input type="text" id="loraUrl" placeholder="https://civitai.com/models/..." />
|
||||
<div class="error-message" id="urlError"></div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="primary-btn" onclick="downloadManager.validateAndFetchVersions()">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Version Selection -->
|
||||
<div class="download-step" id="versionStep" style="display: none;">
|
||||
<div class="version-list" id="versionList">
|
||||
<!-- Versions will be inserted here dynamically -->
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="secondary-btn" onclick="downloadManager.backToUrl()">Back</button>
|
||||
<button class="primary-btn" onclick="downloadManager.proceedToLocation()">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Location Selection -->
|
||||
<div class="download-step" id="locationStep" style="display: none;">
|
||||
<div class="location-selection">
|
||||
<!-- Move path preview to top -->
|
||||
<div class="path-preview">
|
||||
<label>Download Location Preview:</label>
|
||||
<div class="path-display" id="targetPathDisplay">
|
||||
<span class="path-text">Select a LoRA root directory</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Select LoRA Root:</label>
|
||||
<select id="loraRoot"></select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Target Folder:</label>
|
||||
<div class="folder-browser" id="folderBrowser">
|
||||
{% for folder in folders %}
|
||||
{% if folder %}
|
||||
<div class="folder-item" data-folder="{{ folder }}">
|
||||
{{ folder }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="newFolder">New Folder (optional):</label>
|
||||
<input type="text" id="newFolder" placeholder="Enter folder name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="secondary-btn" onclick="downloadManager.backToVersions()">Back</button>
|
||||
<button class="primary-btn" onclick="downloadManager.startDownload()">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Move Model Modal -->
|
||||
<div id="moveModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="moveModalTitle">Move Model</h2>
|
||||
<span class="close" onclick="modalManager.closeModal('moveModal')">×</span>
|
||||
</div>
|
||||
<div class="location-selection">
|
||||
<div class="path-preview">
|
||||
<label>Target Location Preview:</label>
|
||||
<div class="path-display" id="moveTargetPathDisplay">
|
||||
<span class="path-text">Select a LoRA root directory</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Select LoRA Root:</label>
|
||||
<select id="moveLoraRoot"></select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Target Folder:</label>
|
||||
<div class="folder-browser" id="moveFolderBrowser">
|
||||
{% for folder in folders %}
|
||||
{% if folder %}
|
||||
<div class="folder-item" data-folder="{{ folder }}">
|
||||
{{ folder }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="moveNewFolder">New Folder (optional):</label>
|
||||
<input type="text" id="moveNewFolder" placeholder="Enter folder name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="cancel-btn" onclick="modalManager.closeModal('moveModal')">Cancel</button>
|
||||
<button class="primary-btn" onclick="moveManager.moveModel()">Move</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Modal -->
|
||||
<div id="settingsModal" class="modal">
|
||||
<div class="modal-content settings-modal">
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %}
|
||||
{% block init_check_url %}/api/loras?page=1&page_size=1{% endblock %}
|
||||
|
||||
{% block additional_components %}
|
||||
{% include 'components/lora_modals.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'components/controls.html' %}
|
||||
<!-- Lora卡片容器 -->
|
||||
|
||||
Reference in New Issue
Block a user