Files
alexopus-ComfyUI-Notes-Sidebar/js/components/AppendMenu.js
T
2025-07-20 01:08:13 +02:00

178 lines
6.1 KiB
JavaScript

import { NotesApi } from "../api/notesApi.js";
export class AppendMenu {
constructor(textArea, onContentChange) {
this.textArea = textArea;
this.onContentChange = onContentChange;
this.container = null;
this.button = null;
this.submenu = null;
this.isDisabled = true;
}
createMenuElements() {
// Append submenu container
this.container = document.createElement('div');
this.container.className = 'notes-submenu-container';
this.button = document.createElement('button');
this.button.innerHTML = '<i class="pi pi-plus-circle"></i>';
this.button.className = 'notes-btn append-loras';
this.button.title = 'Append';
this.button.onclick = () => this.toggleMenu();
this.button.disabled = this.isDisabled;
// Create submenu
this.submenu = document.createElement('div');
this.submenu.className = 'notes-submenu';
this.submenu.style.display = 'none';
// Create submenu items
const rawOption = document.createElement('div');
rawOption.className = 'notes-submenu-item';
rawOption.textContent = 'Append raw LoRA filenames list';
rawOption.onclick = () => this.selectOption('raw');
const tagOption = document.createElement('div');
tagOption.className = 'notes-submenu-item';
tagOption.textContent = "Append LoRAs in '<lora:name>' format";
tagOption.onclick = () => this.selectOption('tag');
const metaOption = document.createElement('div');
metaOption.className = 'notes-submenu-item';
metaOption.textContent = "Append LoRAs in '<lora:name>, metadata' format";
metaOption.onclick = () => this.selectOption('meta');
this.submenu.appendChild(rawOption);
this.submenu.appendChild(tagOption);
this.submenu.appendChild(metaOption);
this.container.appendChild(this.button);
this.container.appendChild(this.submenu);
return this.container;
}
setDisabled(disabled) {
this.isDisabled = disabled;
if (this.button) {
this.button.disabled = disabled;
}
}
toggleMenu() {
if (this.submenu.style.display === 'none') {
this.submenu.style.display = 'block';
// Add click listener to close menu when clicking outside
document.addEventListener('click', this.closeMenuHandler);
} else {
this.submenu.style.display = 'none';
document.removeEventListener('click', this.closeMenuHandler);
}
}
closeMenuHandler = (event) => {
if (!this.container.contains(event.target)) {
this.submenu.style.display = 'none';
document.removeEventListener('click', this.closeMenuHandler);
}
}
selectOption(type) {
this.submenu.style.display = 'none';
document.removeEventListener('click', this.closeMenuHandler);
switch(type) {
case 'raw':
this.appendLorasList();
break;
case 'tag':
this.appendLorasTags();
break;
case 'meta':
this.appendLorasWithMetadata();
break;
}
}
async appendLorasList() {
try {
const loras = await NotesApi.getLorasList();
// Normalize backslashes to forward slashes
const normalizedLoras = loras.map(lora => lora.replace(/\\/g, '/'));
const lorasText = normalizedLoras.join('\n');
this.insertTextIntoTextarea(lorasText);
} catch (error) {
console.error('Error appending LoRAs:', error);
alert('Failed to append LoRAs list');
}
}
async appendLorasTags() {
try {
const loras = await NotesApi.getLorasList();
// Format each LoRA as <lora:name:1.0>, stripping .safetensors extension and normalizing slashes
const lorasTags = loras.map(lora => {
const nameWithoutExt = lora.replace(/\.safetensors$/i, '');
const normalizedPath = nameWithoutExt.replace(/\\/g, '/');
return `<lora:${normalizedPath}>`;
});
const lorasText = lorasTags.join('\n');
this.insertTextIntoTextarea(lorasText);
} catch (error) {
console.error('Error appending LoRAs tags:', error);
alert('Failed to append LoRAs tags');
}
}
async appendLorasWithMetadata() {
try {
const loras = await NotesApi.getLorasWithMetadata();
// Format each LoRA with metadata as <lora:name:1.0>, metadata
const lorasWithMeta = loras.map(lora => {
const nameWithoutExt = lora.name.replace(/\.safetensors$/i, '');
const normalizedPath = nameWithoutExt.replace(/\\/g, '/');
const baseTag = `<lora:${normalizedPath}>`;
if (lora.metadata) {
return `${baseTag}, ${lora.metadata}`;
} else {
return baseTag;
}
});
const lorasText = lorasWithMeta.join('\n');
this.insertTextIntoTextarea(lorasText);
} catch (error) {
console.error('Error appending LoRAs with metadata:', error);
alert('Failed to append LoRAs with metadata');
}
}
insertTextIntoTextarea(text) {
if (!this.textArea) return;
// Add newline before appending if current content doesn't end with one
const separator = this.textArea.value && !this.textArea.value.endsWith('\n') ? '\n' : '';
const textToInsert = separator + text;
// Focus textarea to ensure it's active
this.textArea.focus();
// Move cursor to end
this.textArea.setSelectionRange(this.textArea.value.length, this.textArea.value.length);
// Use document.execCommand to preserve undo history
document.execCommand('insertText', false, textToInsert);
// Trigger change handling
if (this.onContentChange) {
this.onContentChange();
}
}
}