Files
diodiogod-TTS-Audio-Suite/web/editor-state.js
diodiogod 47f09ba89b Improve Multiline TTS Tag Editor find and replace UX
- add inline find/replace controls with keyboard shortcuts and match navigation
- add replace and replace all flows with persistent search options and highlighting
- add collapsible left panel control while preserving existing resize behavior
- refine panel handle interaction and styling to avoid splitter conflicts during drag
2026-04-08 10:14:25 -03:00

122 lines
3.4 KiB
JavaScript

/**
* 🏷️ Editor State Management
* Handles persistent state for the multiline TTS tag editor
*/
export class EditorState {
constructor() {
this.text = `[pause:1s] Enter your text here...
Examples:
[Alice] Hello there!
[Bob|seed:42] Nice to meet you.
text text [char] more text [pause:1s]
SRT example:
1
00:00:00,000 --> 00:00:03,000
[Alice] Welcome to this presentation.
2
00:00:03,500 --> 00:00:07,000
[en:Bob|seed:42] Let me explain the details.
3
00:00:07,500 --> 00:00:10,000
[Alice|temperature:0.5] Thank you for listening!`;
this.history = [];
this.historyIndex = -1;
this.presets = {};
this.lastCharacter = "";
this.lastLanguage = "";
this.lastSeed = 0;
this.lastTemperature = 0.7;
this.lastPauseDuration = "1s";
this.lastParameterType = "";
this.sidebarExpanded = true;
this.lastCursorPosition = 0;
this.discoveredCharacters = {};
this.fontSize = 14;
this.fontFamily = "monospace";
this.sidebarWidth = 220;
this.uiScale = 1.0;
this.lastWorkflowValue = ""; // Track the last workflow value we loaded to detect file changes
this.findReplaceOpen = false;
this.findReplaceMode = "find";
this.findMatchCase = false;
this.findWholeWord = false;
this.findRegex = false;
this.findSelectionOnly = false;
}
addToHistory(text, caretPos = 0) {
if (this.historyIndex < this.history.length - 1) {
this.history = this.history.slice(0, this.historyIndex + 1);
}
this.history.push({ text, caretPos });
this.historyIndex = this.history.length - 1;
if (this.history.length > 100) {
this.history = this.history.slice(-100);
this.historyIndex = this.history.length - 1;
}
this.text = text;
}
undo() {
if (this.historyIndex > 0) {
this.historyIndex--;
const entry = this.history[this.historyIndex];
this.text = entry.text;
return entry;
}
const current = this.history[this.historyIndex] || { text: this.text, caretPos: 0 };
return current;
}
redo() {
if (this.historyIndex < this.history.length - 1) {
this.historyIndex++;
const entry = this.history[this.historyIndex];
this.text = entry.text;
return entry;
}
const current = this.history[this.historyIndex] || { text: this.text, caretPos: 0 };
return current;
}
getHistoryStatus() {
return `${this.historyIndex + 1}/${this.history.length}`;
}
serialize() {
return JSON.stringify(this);
}
static deserialize(json) {
try {
const data = JSON.parse(json);
const state = new EditorState();
Object.assign(state, data);
return state;
} catch (e) {
console.warn("Failed to deserialize state:", e);
return new EditorState();
}
}
saveToLocalStorage(key) {
localStorage.setItem(key, this.serialize());
}
static loadFromLocalStorage(key) {
const json = localStorage.getItem(key);
if (json) {
return EditorState.deserialize(json);
}
return new EditorState();
}
}