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 = ''; 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 '' format"; tagOption.onclick = () => this.selectOption('tag'); const metaOption = document.createElement('div'); metaOption.className = 'notes-submenu-item'; metaOption.textContent = "Append LoRAs in ', 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 , stripping .safetensors extension and normalizing slashes const lorasTags = loras.map(lora => { const nameWithoutExt = lora.replace(/\.safetensors$/i, ''); const normalizedPath = nameWithoutExt.replace(/\\/g, '/'); return ``; }); 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 , metadata const lorasWithMeta = loras.map(lora => { const nameWithoutExt = lora.name.replace(/\.safetensors$/i, ''); const normalizedPath = nameWithoutExt.replace(/\\/g, '/'); const baseTag = ``; 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(); } } }