feat(megaprompt-v4): on-screen custom text input and frozen prompt editor
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6b97a20329
commit
1fbddff39a
@@ -114,6 +114,36 @@ test("removing the node twice is safe and leaves nothing running", async () => {
|
||||
const mine = fake.observers.slice(obsBefore); assert.ok(mine.length >= 1 && mine.every((o) => o.disconnected));
|
||||
});
|
||||
|
||||
test("inline edit pins a custom subject and rerolls that reel", async () => {
|
||||
const node = await createNode(); api.responders["/isulion/megaprompt_v4/roll"] = payload();
|
||||
const j = node._jackpot; click(j.ui.reels.subject.btns.edit);
|
||||
assert.equal(j.ui.editor.panel.hidden, false); j.ui.editor.input.value = " my elf queen ";
|
||||
j.ui.editor.input.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" })); await tick();
|
||||
assert.equal(lastRoll().body.state.reels.subject.custom, "my elf queen"); assert.deepEqual(lastRoll().body.reels, ["subject"]);
|
||||
assert.equal(j.ui.editor.panel.hidden, true);
|
||||
});
|
||||
test("escape cancels the inline edit", async () => {
|
||||
const node = await createNode(); const before = api.calls.length; const j = node._jackpot;
|
||||
click(j.ui.reels.location.btns.edit); j.ui.editor.input.value = "x";
|
||||
j.ui.editor.input.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
|
||||
assert.equal(j.state.reels.location.custom, ""); assert.equal(api.calls.length, before); assert.equal(j.ui.editor.panel.hidden, true);
|
||||
});
|
||||
test("clear button removes the custom text and rerolls", async () => {
|
||||
const node = await createNode(); api.responders["/isulion/megaprompt_v4/roll"] = payload(); const j = node._jackpot;
|
||||
j.state.reels.location.custom = "my castle"; click(j.ui.reels.location.btns.edit);
|
||||
assert.equal(j.ui.editor.input.value, "my castle"); click(j.ui.editor.clear); await tick();
|
||||
assert.equal(lastRoll().body.state.reels.location.custom, ""); assert.deepEqual(lastRoll().body.reels, ["location"]);
|
||||
});
|
||||
test("edit prompt freezes it and the lever unfreezes", async () => {
|
||||
const node = await createNode(); api.responders["/isulion/megaprompt_v4/roll"] = payload({ rolled: [], segments: [{ reel: "frozen", text: "fixed text" }], prompt: "fixed text", state: { ...readState(null), frozen_prompt: "fixed text" } });
|
||||
const j = node._jackpot; click(j.ui.editBtn); j.ui.editor.textarea.value = "fixed text";
|
||||
click(j.ui.editor.ok); await tick();
|
||||
assert.equal(lastRoll().body.state.frozen_prompt, "fixed text"); assert.deepEqual(lastRoll().body.reels, []); await tick();
|
||||
assert.equal(j.ui.frozenBadge.hidden, false);
|
||||
click(j.ui.lever); await tick();
|
||||
assert.equal(lastRoll().body.state.frozen_prompt, ""); assert.deepEqual(lastRoll().body.reels, REELS);
|
||||
});
|
||||
|
||||
// --- runner (keep last) ---------------------------------------------------
|
||||
let failures = 0;
|
||||
for (const [name, fn] of tests) {
|
||||
|
||||
+65
-3
@@ -278,6 +278,17 @@ class PromptJackpot {
|
||||
const ok = el("button");
|
||||
row.append(clear, cancel, ok);
|
||||
panel.append(input, textarea, row);
|
||||
const onKey = (e) => {
|
||||
e.stopPropagation(); // Delete/Backspace must not reach LiteGraph while typing
|
||||
if (e.key === "Escape") this.closeEditor();
|
||||
if (e.key === "Enter" && e.target === input) this.confirmEditor();
|
||||
};
|
||||
input.addEventListener("keydown", onKey);
|
||||
textarea.addEventListener("keydown", onKey);
|
||||
ok.addEventListener("click", () => this.confirmEditor());
|
||||
cancel.addEventListener("click", () => this.closeEditor());
|
||||
clear.addEventListener("click", () => this.clearCustom());
|
||||
panel.addEventListener("pointerdown", (e) => { if (e.target === panel) this.closeEditor(); });
|
||||
this.ui.editor = { panel, input, textarea, clear, cancel, ok };
|
||||
return panel;
|
||||
}
|
||||
@@ -481,9 +492,60 @@ class PromptJackpot {
|
||||
this.ui.search.list.replaceChildren(...rows);
|
||||
}
|
||||
|
||||
// inline editors (Tâche 9)
|
||||
openInlineEdit() {}
|
||||
openPromptEditor() {}
|
||||
// on-screen editors: custom subject/location text, or the whole frozen prompt
|
||||
openInlineEdit(reel) {
|
||||
const { panel, input, textarea, clear } = this.ui.editor;
|
||||
this.editing = { reel };
|
||||
input.hidden = false;
|
||||
clear.hidden = false;
|
||||
textarea.hidden = true;
|
||||
input.value = this.state.reels[reel].custom;
|
||||
panel.hidden = false;
|
||||
input.focus();
|
||||
}
|
||||
|
||||
openPromptEditor() {
|
||||
const { panel, input, textarea, clear } = this.ui.editor;
|
||||
this.editing = { prompt: true };
|
||||
input.hidden = true;
|
||||
clear.hidden = true;
|
||||
textarea.hidden = false;
|
||||
textarea.value = this.state.frozen_prompt || (this.view.last?.prompt ?? "");
|
||||
panel.hidden = false;
|
||||
textarea.focus();
|
||||
}
|
||||
|
||||
closeEditor() {
|
||||
this.editing = null;
|
||||
this.ui.editor.panel.hidden = true;
|
||||
}
|
||||
|
||||
confirmEditor() {
|
||||
const editing = this.editing;
|
||||
if (!editing) return;
|
||||
this.closeEditor();
|
||||
if (editing.prompt) {
|
||||
this.state.frozen_prompt = this.ui.editor.textarea.value;
|
||||
this.commit();
|
||||
this.roll([]);
|
||||
} else {
|
||||
this.setCustom(editing.reel, this.ui.editor.input.value.trim());
|
||||
}
|
||||
}
|
||||
|
||||
clearCustom() {
|
||||
const editing = this.editing;
|
||||
if (!editing?.reel) return;
|
||||
this.closeEditor();
|
||||
this.setCustom(editing.reel, "");
|
||||
}
|
||||
|
||||
setCustom(reel, text) {
|
||||
this.state.reels[reel].custom = text;
|
||||
this.commit();
|
||||
this.renderReel(reel);
|
||||
this.roll([reel]);
|
||||
}
|
||||
|
||||
// history (Tâche 10)
|
||||
pushHistory() {}
|
||||
|
||||
Reference in New Issue
Block a user