helwasm: store-on-correct, store button reflects existence, use stored spec
- new read-only export hel_entry(name): the entry's canonical stored form, or "" - Mark correct now also stores the name (keeps the entry); unmark keeps the stored name and just drops the hash (wraps add/rm for an ephemeral entry so the right hash is removed) - Store button shows "Stored ✓" (disabled, ocean outline) when the name is already in the catalog, "Store" otherwise - when a typed name already exists, the field adopts the full stored spec on blur (real mode/seq/date/parent) instead of a default-extended parse
This commit is contained in:
+34
-12
@@ -201,7 +201,7 @@
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import init, { hel_init, hel_command, hel_load_script, hel_parse, hel_parse_name } from "./pkg/helwasm.js";
|
||||
import init, { hel_init, hel_command, hel_load_script, hel_parse, hel_parse_name, hel_entry } from "./pkg/helwasm.js";
|
||||
|
||||
const $ = (s) => document.querySelector(s);
|
||||
const masterEl = () => document.getElementById("master");
|
||||
@@ -265,6 +265,15 @@
|
||||
// only the one-way "correct" hash is persisted on the device.
|
||||
let lastSecret = "";
|
||||
let appliedMaster = null; // last master value pushed to the engine (debounce hint)
|
||||
function refreshStoreBtn(name) {
|
||||
const b = $("#store");
|
||||
if (!b) return;
|
||||
const exists = name ? !!hel_entry(name) : false;
|
||||
b.classList.toggle("is-stored", exists);
|
||||
b.disabled = exists || !name;
|
||||
b.textContent = exists ? "Stored ✓" : "Store";
|
||||
b.title = exists ? "This name is already in your catalog" : "Save this name in this browser";
|
||||
}
|
||||
function refreshCorrectBtn(enabled, isCorrect) {
|
||||
const b = $("#markCorrect");
|
||||
if (!b) return;
|
||||
@@ -287,6 +296,7 @@
|
||||
sec.textContent = ""; sec.classList.remove("correct");
|
||||
lenEl.textContent = ""; lastSecret = "";
|
||||
refreshCorrectBtn(false, false);
|
||||
refreshStoreBtn("");
|
||||
return;
|
||||
}
|
||||
const master = masterEl().value;
|
||||
@@ -316,6 +326,7 @@
|
||||
sec.classList.toggle("correct", correct);
|
||||
lenEl.textContent = pw ? "len " + pw.length : "";
|
||||
refreshCorrectBtn(!!pw, correct);
|
||||
refreshStoreBtn(name);
|
||||
if (!pw && !silent) toast("No output");
|
||||
}
|
||||
function toggleCorrect() {
|
||||
@@ -324,19 +335,25 @@
|
||||
const spec = $("#qname").value.trim();
|
||||
const name = hel_parse_name(spec);
|
||||
if (!name) return;
|
||||
const verb = b.classList.contains("is-correct") ? "uncorrect " : "correct ";
|
||||
// Mark / unmark THIS name + master on the device (stores SHA1(name‖password)).
|
||||
// The entry may be ephemeral (not Stored), so wrap add/rm around it so
|
||||
// correct/uncorrect can recompute the password to hash — same as the console.
|
||||
if (/^error: name .* not found/m.test(hel_command("enc " + name))) {
|
||||
hel_command("add " + spec);
|
||||
hel_command(verb + name);
|
||||
hel_command("rm " + name);
|
||||
const marking = !b.classList.contains("is-correct");
|
||||
const exists = !!hel_entry(name);
|
||||
// Marking correct also STORES the name (you only confirm things you keep), so
|
||||
// the entry stays in the catalog. The hash is SHA1(name‖password) on the device.
|
||||
if (marking) {
|
||||
if (!exists) hel_command("add " + spec); // store it if new
|
||||
hel_command("correct " + name);
|
||||
persist();
|
||||
} else if (exists) {
|
||||
hel_command("uncorrect " + name); // drop the hash; keep the stored name
|
||||
} else {
|
||||
hel_command(verb + name);
|
||||
// not stored (e.g. a stale hash): wrap add/rm so uncorrect can recompute the
|
||||
// password to remove the right hash, without leaving the entry behind.
|
||||
hel_command("add " + spec);
|
||||
hel_command("uncorrect " + name);
|
||||
hel_command("rm " + name);
|
||||
}
|
||||
quickGen(true);
|
||||
toast(verb === "correct " ? "Marked correct" : "No longer marked correct");
|
||||
toast(marking ? "Marked correct & stored" : "No longer marked correct");
|
||||
}
|
||||
function quickStore() {
|
||||
const spec = $("#qname").value.trim();
|
||||
@@ -345,6 +362,7 @@
|
||||
const out = hel_command("add " + spec);
|
||||
persist();
|
||||
appendLine('<span class="muted"># stored ' + esc(name) + "</span>");
|
||||
refreshStoreBtn(name);
|
||||
toast(/^(error|warning)/m.test(out) ? out.split("\n")[0] : "Stored " + name);
|
||||
}
|
||||
|
||||
@@ -462,7 +480,11 @@
|
||||
$("#qname").addEventListener("blur", () => {
|
||||
const spec = $("#qname").value.trim();
|
||||
if (!spec) return;
|
||||
const norm = hel_parse(spec);
|
||||
// If the name is already in the catalog, use its FULL stored spec (real
|
||||
// mode/seq/date/parent), not a fresh default-extended parse of what was typed.
|
||||
const name = hel_parse_name(spec);
|
||||
const stored = name ? hel_entry(name) : "";
|
||||
const norm = stored || hel_parse(spec);
|
||||
if (norm && norm !== spec) {
|
||||
$("#qname").value = norm;
|
||||
quickGen(true);
|
||||
|
||||
Vendored
+10
-1
@@ -6,6 +6,14 @@
|
||||
*/
|
||||
export function hel_command(cmd: string): string;
|
||||
|
||||
/**
|
||||
* Look up an entry by its exact name and return its canonical stored form
|
||||
* (`name [len]mode seq date comment ^parent`), or "" if it is not in the catalog.
|
||||
* Read-only. The UI uses this to detect "already stored" and to use the real stored
|
||||
* spec (its mode/seq/date/parent) instead of the bare name the user typed.
|
||||
*/
|
||||
export function hel_entry(name: string): string;
|
||||
|
||||
/**
|
||||
* Call once at page load: routes Rust panics to the browser console with a
|
||||
* readable message + stack instead of an opaque "unreachable" trap.
|
||||
@@ -38,11 +46,12 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
|
||||
|
||||
export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly hel_init: () => void;
|
||||
readonly hel_command: (a: number, b: number) => [number, number];
|
||||
readonly hel_entry: (a: number, b: number) => [number, number];
|
||||
readonly hel_load_script: (a: number, b: number) => [number, number];
|
||||
readonly hel_parse: (a: number, b: number) => [number, number];
|
||||
readonly hel_parse_name: (a: number, b: number) => [number, number];
|
||||
readonly hel_init: () => void;
|
||||
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
|
||||
@@ -20,6 +20,29 @@ export function hel_command(cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an entry by its exact name and return its canonical stored form
|
||||
* (`name [len]mode seq date comment ^parent`), or "" if it is not in the catalog.
|
||||
* Read-only. The UI uses this to detect "already stored" and to use the real stored
|
||||
* spec (its mode/seq/date/parent) instead of the bare name the user typed.
|
||||
* @param {string} name
|
||||
* @returns {string}
|
||||
*/
|
||||
export function hel_entry(name) {
|
||||
let deferred2_0;
|
||||
let deferred2_1;
|
||||
try {
|
||||
const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.hel_entry(ptr0, len0);
|
||||
deferred2_0 = ret[0];
|
||||
deferred2_1 = ret[1];
|
||||
return getStringFromWasm0(ret[0], ret[1]);
|
||||
} finally {
|
||||
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call once at page load: routes Rust panics to the browser console with a
|
||||
* readable message + stack instead of an opaque "unreachable" trap.
|
||||
|
||||
Binary file not shown.
Vendored
+2
-1
@@ -1,11 +1,12 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export const hel_init: () => void;
|
||||
export const hel_command: (a: number, b: number) => [number, number];
|
||||
export const hel_entry: (a: number, b: number) => [number, number];
|
||||
export const hel_load_script: (a: number, b: number) => [number, number];
|
||||
export const hel_parse: (a: number, b: number) => [number, number];
|
||||
export const hel_parse_name: (a: number, b: number) => [number, number];
|
||||
export const hel_init: () => void;
|
||||
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
||||
export const __wbindgen_malloc: (a: number, b: number) => number;
|
||||
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
|
||||
@@ -46,6 +46,20 @@ pub fn hel_parse_name(spec: String) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Look up an entry by its exact name and return its canonical stored form
|
||||
/// (`name [len]mode seq date comment ^parent`), or "" if it is not in the catalog.
|
||||
/// Read-only. The UI uses this to detect "already stored" and to use the real stored
|
||||
/// spec (its mode/seq/date/parent) instead of the bare name the user typed.
|
||||
#[wasm_bindgen]
|
||||
pub fn hel_entry(name: String) -> String {
|
||||
let cell = STATE.lock();
|
||||
let lk = cell.borrow();
|
||||
match lk.db.get(&name).or_else(|| lk.ls.get(&name)) {
|
||||
Some(p) => p.lock().borrow().to_string().trim().to_string(),
|
||||
None => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a whole multi-line script (every `add …` line, `set …`, etc.) against the
|
||||
/// shared state in one call. Used to bulk-import a pasted catalog (e.g. the text
|
||||
/// of the Notion page) and to load the persisted catalog from localStorage.
|
||||
|
||||
@@ -185,6 +185,9 @@ input.mask.revealed { -webkit-text-security: none; }
|
||||
.btn.small.is-correct { background: var(--ocean); color: var(--cream); border-color: var(--ocean); }
|
||||
.btn.small.is-correct:hover { background: var(--deep); border-color: var(--deep); }
|
||||
.btn:disabled { opacity: .4; cursor: not-allowed; pointer-events: none; }
|
||||
/* "Stored ✓": not an action (disabled), but shown as a confirmed ocean outline
|
||||
rather than the dimmed disabled look. */
|
||||
.btn.small.is-stored { opacity: 1; background: transparent; color: var(--ocean); border-color: var(--ocean); }
|
||||
|
||||
/* Quick-gen result row */
|
||||
.result {
|
||||
|
||||
Reference in New Issue
Block a user