Skip to content

Commit c15fccd

Browse files
committed
Trim JSON-editor comments to the load-bearing constraints
1 parent fda8d2d commit c15fccd

2 files changed

Lines changed: 13 additions & 40 deletions

File tree

quilt-sync/ui/js/json-editor-glue.js

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
1-
// Thin wrapper around vanilla-jsoneditor that exposes the three functions
2-
// consumed by the Leptos commit page via wasm-bindgen.
3-
//
41
// Bundled by esbuild during `trunk build` (see Trunk.toml hook).
52
import { createJSONEditor } from "vanilla-jsoneditor/standalone.js";
63

7-
// Registry keyed by the editor's DOM element, NOT an id string. During the
8-
// commit page's keep-alive subtree swap (the outer `Transition`), an old and a
9-
// new editor container are alive at once; keying by id — or resolving via
10-
// `document.getElementById` — would be ambiguous by construction and let a
11-
// replaced subtree's cleanup kill its successor's editor. Element identity never
12-
// is. A WeakMap needs no manual eviction to avoid leaks, and `destroy` still
13-
// deletes its entry so the same element is never destroyed twice.
4+
// Keyed by DOM element, never by id: the commit page's `Transition` keeps an
5+
// old and new editor container alive at once, so an id (or `getElementById`)
6+
// could resolve to the wrong one and let a stale cleanup destroy the live
7+
// editor. Element identity can't. WeakMap avoids manual eviction.
148
const editors = new WeakMap();
159

1610
function mountEditor(target, textarea, initialValue) {
1711
if (!target || editors.has(target)) return;
18-
// Hide the textarea fallback belonging to THIS dialog. The textarea element
19-
// is passed in (not looked up by id) so we always hide the current dialog's
20-
// fallback, never another dialog's during a swap.
2112
if (textarea && textarea.parentElement)
2213
textarea.parentElement.style.display = "none";
2314
const editor = createJSONEditor({
@@ -29,12 +20,8 @@ function mountEditor(target, textarea, initialValue) {
2920
if (updatedContent.json !== undefined)
3021
textarea.value = JSON.stringify(updatedContent.json);
3122
else textarea.value = updatedContent.text ?? "";
32-
// Mirror the edit into the (hidden) textarea AND notify Leptos: a
33-
// programmatic `value` assignment does not fire an `input` event, so
34-
// dispatch one so the commit page's live-validation signal tracks
35-
// metadata edits made through the JSON editor. The textarea is captured
36-
// from this closure, so the write always targets the CURRENT dialog's
37-
// textarea, never the first `#metadata` match in the document.
23+
// Assigning `.value` does not fire `input`; dispatch one so the
24+
// commit page's live-validation signal sees edits made in the editor.
3825
textarea.dispatchEvent(new Event("input", { bubbles: true }));
3926
},
4027
navigationBar: false,

quilt-sync/ui/src/pages/commit.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -861,12 +861,8 @@ fn field_violation_view(
861861

862862
// ── JSON editor integration ──
863863

864-
// The wasm-bindgen boundary passes the editor's own DOM element (and, for
865-
// create, the dialog's textarea) rather than an id string. Keying the JS-side
866-
// registry by element identity is what makes the keep-alive `Transition` swap
867-
// safe: an old and a new container are alive at once, so an id key (and
868-
// `getElementById`) would be ambiguous and let an old subtree's cleanup destroy
869-
// the new subtree's editor. See json-editor-glue.js.
864+
// The boundary passes DOM elements, not id strings, so the JS registry can key
865+
// by element identity — see the `Transition`-safety note in json-editor-glue.js.
870866
#[wasm_bindgen::prelude::wasm_bindgen]
871867
extern "C" {
872868
#[wasm_bindgen(js_namespace = ["window"], js_name = "__getJsonEditorValue")]
@@ -883,9 +879,8 @@ extern "C" {
883879
fn destroy_json_editor_js(target: &web_sys::HtmlElement);
884880
}
885881

886-
/// Read the committed metadata at submit: prefer the JSON editor's live value,
887-
/// keyed by its own element; fall back to this dialog's textarea when the editor
888-
/// never mounted or is empty.
882+
/// Read the committed metadata at submit: the editor's live value, or this
883+
/// dialog's textarea when the editor never mounted or is empty.
889884
fn get_json_editor_value(
890885
editor_ref: NodeRef<html::Div>,
891886
textarea_ref: NodeRef<html::Textarea>,
@@ -908,15 +903,9 @@ fn JsonEditor(
908903
textarea_ref: NodeRef<html::Textarea>,
909904
initial_value: String,
910905
) -> impl IntoView {
911-
// Mount once BOTH the editor container and this dialog's textarea are in the
912-
// DOM. The textarea appears earlier in the view than the editor `<div>`, so
913-
// rather than assume a load order (and silently skip when the textarea's
914-
// `NodeRef` is not yet set — the same silent-failure class as the old
915-
// `getElementById` miss), the mount is driven off `on_load` for both nodes
916-
// and fires on whichever loads last. `on_load` guarantees each node is
917-
// connected, and mounting targets exactly those elements — never a global
918-
// lookup — so a concurrent keep-alive swap can never resolve to the wrong
919-
// dialog's nodes.
906+
// Mount needs both the editor div and the textarea loaded, and their load
907+
// order isn't guaranteed, so drive it off both `on_load`s and fire on
908+
// whichever lands last (the guard makes the other a no-op).
920909
let mounted = StoredValue::new(false);
921910
let init = StoredValue::new(initial_value);
922911
let try_mount = move || {
@@ -934,9 +923,6 @@ fn JsonEditor(
934923
node_ref.on_load(move |_| try_mount());
935924
textarea_ref.on_load(move |_| try_mount());
936925

937-
// Destroy exactly this element's editor. Because the registry is keyed by
938-
// element, a replaced subtree's cleanup can never kill its successor's
939-
// instance regardless of mount/cleanup ordering.
940926
on_cleanup(move || {
941927
if let Some(editor) = node_ref.get_untracked() {
942928
destroy_json_editor_js(&editor);

0 commit comments

Comments
 (0)