Use state and store
This commit is contained in:
+2
-1
@@ -1 +1,2 @@
|
||||
__pycache__
|
||||
__pycache__
|
||||
notes/
|
||||
+170
-67
@@ -6,19 +6,143 @@ link.rel = 'stylesheet';
|
||||
link.href = '/extensions/comfyui-notes-sidebar/notes-sidebar.css';
|
||||
document.head.appendChild(link);
|
||||
|
||||
class NotesStore extends EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
notes: [],
|
||||
activeNote: null,
|
||||
unsavedChanges: new Map(), // noteName -> boolean
|
||||
noteContent: new Map(), // noteName -> string (current content)
|
||||
savedContent: new Map() // noteName -> string (last saved content)
|
||||
};
|
||||
}
|
||||
|
||||
getState() {
|
||||
return { ...this.state };
|
||||
}
|
||||
|
||||
setState(updates) {
|
||||
const prevState = { ...this.state };
|
||||
this.state = { ...this.state, ...updates };
|
||||
|
||||
// Emit state change event
|
||||
this.dispatchEvent(new CustomEvent('stateChanged', {
|
||||
detail: {
|
||||
prevState,
|
||||
newState: this.getState(),
|
||||
updates
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// Convenience methods for common state operations
|
||||
setNotes(notes) {
|
||||
this.setState({ notes });
|
||||
}
|
||||
|
||||
setActiveNote(activeNote) {
|
||||
this.setState({ activeNote });
|
||||
}
|
||||
|
||||
setNoteContent(noteName, content) {
|
||||
const noteContent = new Map(this.state.noteContent);
|
||||
noteContent.set(noteName, content);
|
||||
this.setState({ noteContent });
|
||||
}
|
||||
|
||||
setSavedContent(noteName, content) {
|
||||
const savedContent = new Map(this.state.savedContent);
|
||||
savedContent.set(noteName, content);
|
||||
this.setState({ savedContent });
|
||||
}
|
||||
|
||||
setUnsavedChanges(noteName, hasChanges) {
|
||||
const unsavedChanges = new Map(this.state.unsavedChanges);
|
||||
unsavedChanges.set(noteName, hasChanges);
|
||||
this.setState({ unsavedChanges });
|
||||
}
|
||||
|
||||
deleteNoteFromState(noteName) {
|
||||
const unsavedChanges = new Map(this.state.unsavedChanges);
|
||||
const noteContent = new Map(this.state.noteContent);
|
||||
const savedContent = new Map(this.state.savedContent);
|
||||
|
||||
unsavedChanges.delete(noteName);
|
||||
noteContent.delete(noteName);
|
||||
savedContent.delete(noteName);
|
||||
|
||||
this.setState({ unsavedChanges, noteContent, savedContent });
|
||||
}
|
||||
|
||||
renameNoteInState(oldName, newName) {
|
||||
const unsavedChanges = new Map(this.state.unsavedChanges);
|
||||
const noteContent = new Map(this.state.noteContent);
|
||||
const savedContent = new Map(this.state.savedContent);
|
||||
|
||||
// Transfer state from old name to new name
|
||||
const unsavedState = unsavedChanges.get(oldName) || false;
|
||||
const content = noteContent.get(oldName) || '';
|
||||
const saved = savedContent.get(oldName) || '';
|
||||
|
||||
// Remove old
|
||||
unsavedChanges.delete(oldName);
|
||||
noteContent.delete(oldName);
|
||||
savedContent.delete(oldName);
|
||||
|
||||
// Add new
|
||||
unsavedChanges.set(newName, unsavedState);
|
||||
noteContent.set(newName, content);
|
||||
savedContent.set(newName, saved);
|
||||
|
||||
this.setState({ unsavedChanges, noteContent, savedContent });
|
||||
}
|
||||
}
|
||||
|
||||
class NotesSidebar {
|
||||
constructor() {
|
||||
this.notes = [];
|
||||
this.activeNote = null;
|
||||
this.store = new NotesStore();
|
||||
this.tabsContainer = null;
|
||||
this.contentArea = null;
|
||||
this.textArea = null;
|
||||
this.isInitialized = false;
|
||||
this.sidebarElement = null;
|
||||
// Track unsaved changes and content for each note
|
||||
this.unsavedChanges = new Map(); // noteName -> boolean
|
||||
this.noteContent = new Map(); // noteName -> string (current content)
|
||||
this.savedContent = new Map(); // noteName -> string (last saved content)
|
||||
|
||||
// Listen to state changes
|
||||
this.store.addEventListener('stateChanged', (event) => {
|
||||
this.onStateChanged(event.detail);
|
||||
});
|
||||
}
|
||||
|
||||
onStateChanged(changeDetails) {
|
||||
const { prevState, newState, updates } = changeDetails;
|
||||
|
||||
// Update tabs if notes changed, active note changed, or unsaved changes changed
|
||||
if (updates.notes || updates.activeNote || updates.unsavedChanges) {
|
||||
this.renderTabs();
|
||||
}
|
||||
|
||||
// Update textarea if active note changed or note content changed
|
||||
if (updates.activeNote || updates.noteContent) {
|
||||
this.updateTextArea();
|
||||
}
|
||||
}
|
||||
|
||||
get notes() { return this.store.state.notes; }
|
||||
get activeNote() { return this.store.state.activeNote; }
|
||||
get unsavedChanges() { return this.store.state.unsavedChanges; }
|
||||
get noteContent() { return this.store.state.noteContent; }
|
||||
get savedContent() { return this.store.state.savedContent; }
|
||||
|
||||
updateTextArea() {
|
||||
if (!this.textArea || !this.activeNote) return;
|
||||
|
||||
// Check if we have unsaved content for this note
|
||||
if (this.noteContent.has(this.activeNote)) {
|
||||
this.textArea.value = this.noteContent.get(this.activeNote);
|
||||
} else {
|
||||
this.textArea.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
@@ -35,10 +159,9 @@ class NotesSidebar {
|
||||
if (this.isInitialized && this.sidebarElement) {
|
||||
el.innerHTML = '';
|
||||
el.appendChild(this.sidebarElement);
|
||||
// Refresh the active note content when reopening
|
||||
if (this.activeNote) {
|
||||
this.loadNoteContent(this.activeNote);
|
||||
}
|
||||
// Trigger reactive updates when reopening
|
||||
this.renderTabs();
|
||||
this.updateTextArea();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -127,15 +250,15 @@ class NotesSidebar {
|
||||
try {
|
||||
const response = await fetch('/notes_sidebar/list');
|
||||
const data = await response.json();
|
||||
this.notes = data.notes || [];
|
||||
const notes = data.notes || [];
|
||||
|
||||
if (this.notes.length > 0 && !this.activeNote) {
|
||||
this.activeNote = this.notes[0];
|
||||
this.store.setNotes(notes);
|
||||
|
||||
if (notes.length > 0 && !this.activeNote) {
|
||||
this.store.setActiveNote(notes[0]);
|
||||
}
|
||||
|
||||
this.renderTabs();
|
||||
|
||||
// Load content for active note after rendering tabs
|
||||
// Load content for active note after setting state
|
||||
if (this.activeNote) {
|
||||
await this.loadNoteContent(this.activeNote);
|
||||
}
|
||||
@@ -145,6 +268,8 @@ class NotesSidebar {
|
||||
}
|
||||
|
||||
renderTabs() {
|
||||
if (!this.tabsContainer) return;
|
||||
|
||||
const existingTabs = this.tabsContainer.querySelectorAll('.note-tab');
|
||||
existingTabs.forEach(tab => tab.remove());
|
||||
|
||||
@@ -162,33 +287,28 @@ class NotesSidebar {
|
||||
async selectNote(noteName) {
|
||||
// Save current content before switching
|
||||
if (this.activeNote && this.textArea) {
|
||||
this.noteContent.set(this.activeNote, this.textArea.value);
|
||||
this.store.setNoteContent(this.activeNote, this.textArea.value);
|
||||
}
|
||||
|
||||
this.activeNote = noteName;
|
||||
this.store.setActiveNote(noteName);
|
||||
await this.loadNoteContent(noteName);
|
||||
this.renderTabs();
|
||||
}
|
||||
|
||||
async loadNoteContent(noteName) {
|
||||
try {
|
||||
// Check if we have unsaved content for this note
|
||||
if (this.noteContent.has(noteName)) {
|
||||
// Use the unsaved content
|
||||
if (this.textArea) {
|
||||
this.textArea.value = this.noteContent.get(noteName);
|
||||
}
|
||||
// Content is already in state, updateTextArea will handle it
|
||||
return;
|
||||
} else {
|
||||
// Load from server
|
||||
const response = await fetch(`/notes_sidebar/note/${encodeURIComponent(noteName)}`);
|
||||
const data = await response.json();
|
||||
const content = data.content || '';
|
||||
if (this.textArea) {
|
||||
this.textArea.value = content;
|
||||
}
|
||||
|
||||
// Store both current and saved content
|
||||
this.noteContent.set(noteName, content);
|
||||
this.savedContent.set(noteName, content);
|
||||
this.store.setNoteContent(noteName, content);
|
||||
this.store.setSavedContent(noteName, content);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading note content:', error);
|
||||
@@ -209,10 +329,9 @@ class NotesSidebar {
|
||||
if (response.ok) {
|
||||
console.log('Note saved successfully');
|
||||
// Mark as saved
|
||||
this.savedContent.set(this.activeNote, content);
|
||||
this.noteContent.set(this.activeNote, content);
|
||||
this.unsavedChanges.set(this.activeNote, false);
|
||||
this.renderTabs(); // Update tab display
|
||||
this.store.setSavedContent(this.activeNote, content);
|
||||
this.store.setNoteContent(this.activeNote, content);
|
||||
this.store.setUnsavedChanges(this.activeNote, false);
|
||||
} else {
|
||||
console.error('Error saving note');
|
||||
}
|
||||
@@ -234,17 +353,15 @@ class NotesSidebar {
|
||||
if (response.ok) {
|
||||
// Clean up tracking for deleted note
|
||||
const deletedNote = this.activeNote;
|
||||
this.unsavedChanges.delete(deletedNote);
|
||||
this.noteContent.delete(deletedNote);
|
||||
this.savedContent.delete(deletedNote);
|
||||
this.store.deleteNoteFromState(deletedNote);
|
||||
|
||||
await this.refreshNotes();
|
||||
// Select the first available note or clear if no notes left
|
||||
this.activeNote = this.notes.length > 0 ? this.notes[0] : null;
|
||||
if (this.activeNote) {
|
||||
await this.loadNoteContent(this.activeNote);
|
||||
} else {
|
||||
this.textArea.value = '';
|
||||
const newActiveNote = this.notes.length > 0 ? this.notes[0] : null;
|
||||
this.store.setActiveNote(newActiveNote);
|
||||
|
||||
if (newActiveNote) {
|
||||
await this.loadNoteContent(newActiveNote);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -279,25 +396,17 @@ class NotesSidebar {
|
||||
// Delete old note
|
||||
await fetch(`/notes_sidebar/note/${encodeURIComponent(this.activeNote)}`, { method: 'DELETE' });
|
||||
|
||||
// Update tracking maps
|
||||
// Update tracking maps through store
|
||||
const oldName = this.activeNote;
|
||||
const unsavedState = this.unsavedChanges.get(oldName) || false;
|
||||
const content = this.noteContent.get(oldName) || currentContent;
|
||||
this.store.renameNoteInState(oldName, newName);
|
||||
|
||||
// Remove old tracking
|
||||
this.unsavedChanges.delete(oldName);
|
||||
this.noteContent.delete(oldName);
|
||||
this.savedContent.delete(oldName);
|
||||
|
||||
// Add new tracking
|
||||
this.noteContent.set(newName, content);
|
||||
this.savedContent.set(newName, currentContent); // The content we just saved
|
||||
this.unsavedChanges.set(newName, false); // Just saved, so no unsaved changes
|
||||
// Set saved content to what we just saved
|
||||
this.store.setSavedContent(newName, currentContent);
|
||||
this.store.setUnsavedChanges(newName, false);
|
||||
|
||||
// Update active note and refresh
|
||||
this.activeNote = newName;
|
||||
this.store.setActiveNote(newName);
|
||||
await this.refreshNotes();
|
||||
this.renderTabs();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error renaming note:', error);
|
||||
@@ -317,15 +426,12 @@ class NotesSidebar {
|
||||
|
||||
if (response.ok) {
|
||||
await this.refreshNotes();
|
||||
this.activeNote = noteName;
|
||||
this.textArea.value = '';
|
||||
this.store.setActiveNote(noteName);
|
||||
|
||||
// Initialize tracking for new note
|
||||
this.noteContent.set(noteName, '');
|
||||
this.savedContent.set(noteName, '');
|
||||
this.unsavedChanges.set(noteName, false);
|
||||
|
||||
this.renderTabs();
|
||||
this.store.setNoteContent(noteName, '');
|
||||
this.store.setSavedContent(noteName, '');
|
||||
this.store.setUnsavedChanges(noteName, false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating note:', error);
|
||||
@@ -335,7 +441,7 @@ class NotesSidebar {
|
||||
async refreshNotes() {
|
||||
// Preserve current content before refreshing
|
||||
if (this.activeNote && this.textArea) {
|
||||
this.noteContent.set(this.activeNote, this.textArea.value);
|
||||
this.store.setNoteContent(this.activeNote, this.textArea.value);
|
||||
}
|
||||
|
||||
await this.loadNotes();
|
||||
@@ -348,14 +454,11 @@ class NotesSidebar {
|
||||
const savedContent = this.savedContent.get(this.activeNote) || '';
|
||||
|
||||
// Update current content
|
||||
this.noteContent.set(this.activeNote, currentContent);
|
||||
this.store.setNoteContent(this.activeNote, currentContent);
|
||||
|
||||
// Check if content has changed from saved version
|
||||
const hasUnsavedChanges = currentContent !== savedContent;
|
||||
this.unsavedChanges.set(this.activeNote, hasUnsavedChanges);
|
||||
|
||||
// Update tab display
|
||||
this.renderTabs();
|
||||
this.store.setUnsavedChanges(this.activeNote, hasUnsavedChanges);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user