mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-22 13:42:12 -03:00
Add initialization tracking to prevent multiple event listener attachments in context menu components. Use dataset.initialized flag to ensure NSFW selector events are only set up once per component instance. In ModelContextMenuMixin, replace DOM elements and reattach event listeners to avoid duplicates when components are reinitialized. This fixes issues where multiple click handlers could be attached to the same elements.
81 lines
3.2 KiB
JavaScript
81 lines
3.2 KiB
JavaScript
import { BaseContextMenu } from './BaseContextMenu.js';
|
|
import { ModelContextMenuMixin } from './ModelContextMenuMixin.js';
|
|
import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js';
|
|
import { copyLoraSyntax, sendLoraToWorkflow, buildLoraSyntax } from '../../utils/uiHelpers.js';
|
|
import { showExcludeModal, showDeleteModal } from '../../utils/modalUtils.js';
|
|
import { moveManager } from '../../managers/MoveManager.js';
|
|
|
|
export class LoraContextMenu extends BaseContextMenu {
|
|
constructor() {
|
|
super('loraContextMenu', '.model-card');
|
|
this.nsfwSelector = document.getElementById('nsfwLevelSelector');
|
|
this.modelType = 'lora';
|
|
this.resetAndReload = resetAndReload;
|
|
|
|
// Initialize NSFW Level Selector events only if not already initialized
|
|
if (this.nsfwSelector && !this.nsfwSelector.dataset.initialized) {
|
|
this.initNSFWSelector();
|
|
this.nsfwSelector.dataset.initialized = 'true';
|
|
}
|
|
}
|
|
|
|
// Use the saveModelMetadata implementation from loraApi
|
|
async saveModelMetadata(filePath, data) {
|
|
return getModelApiClient().saveModelMetadata(filePath, data);
|
|
}
|
|
|
|
handleMenuAction(action, menuItem) {
|
|
// First try to handle with common actions
|
|
if (ModelContextMenuMixin.handleCommonMenuActions.call(this, action)) {
|
|
return;
|
|
}
|
|
|
|
// Otherwise handle lora-specific actions
|
|
switch(action) {
|
|
case 'detail':
|
|
// Trigger the main card click which shows the modal
|
|
this.currentCard.click();
|
|
break;
|
|
case 'copyname':
|
|
// Generate and copy LoRA syntax
|
|
copyLoraSyntax(this.currentCard);
|
|
break;
|
|
case 'sendappend':
|
|
// Send LoRA to workflow (append mode)
|
|
this.sendLoraToWorkflow(false);
|
|
break;
|
|
case 'sendreplace':
|
|
// Send LoRA to workflow (replace mode)
|
|
this.sendLoraToWorkflow(true);
|
|
break;
|
|
case 'replace-preview':
|
|
// Add a new action for replacing preview images
|
|
getModelApiClient().replaceModelPreview(this.currentCard.dataset.filepath);
|
|
break;
|
|
case 'delete':
|
|
// Call showDeleteModal directly instead of clicking the trash button
|
|
showDeleteModal(this.currentCard.dataset.filepath);
|
|
break;
|
|
case 'move':
|
|
moveManager.showMoveModal(this.currentCard.dataset.filepath);
|
|
break;
|
|
case 'refresh-metadata':
|
|
getModelApiClient().refreshSingleModelMetadata(this.currentCard.dataset.filepath);
|
|
break;
|
|
case 'exclude':
|
|
showExcludeModal(this.currentCard.dataset.filepath);
|
|
break;
|
|
}
|
|
}
|
|
|
|
sendLoraToWorkflow(replaceMode) {
|
|
const card = this.currentCard;
|
|
const usageTips = JSON.parse(card.dataset.usage_tips || '{}');
|
|
const loraSyntax = buildLoraSyntax(card.dataset.file_name, usageTips);
|
|
|
|
sendLoraToWorkflow(loraSyntax, replaceMode, 'lora');
|
|
}
|
|
}
|
|
|
|
// Mix in shared methods
|
|
Object.assign(LoraContextMenu.prototype, ModelContextMenuMixin); |