diff --git a/frontend/app.js b/frontend/app.js
index 9dd02a3..1a6c923 100644
--- a/frontend/app.js
+++ b/frontend/app.js
@@ -143,6 +143,7 @@ const el = {
copyReproBtn: document.getElementById("copyReproBtn"),
autoLayoutBtn: document.getElementById("autoLayoutBtn"),
autoTidyBtn: document.getElementById("autoTidyBtn"),
+ unlockAllBtn: document.getElementById("unlockAllBtn"),
themeToggleBtn: document.getElementById("themeToggleBtn"),
shortcutsBtn: document.getElementById("shortcutsBtn"),
undoBtn: document.getElementById("undoBtn"),
@@ -1780,6 +1781,7 @@ function bindSvgInteractions() {
const dragRefsRaw = state.selectedRefs.length ? [...state.selectedRefs] : [ref];
const dragRefs = dragRefsRaw.filter((r) => !instanceByRef(r)?.placement?.locked);
if (!dragRefs.length) {
+ el.jsonFeedback.textContent = `${ref} is locked. Uncheck 'Locked' on the component or use 'Unlock All'.`;
return;
}
const baseByRef = {};
@@ -2494,7 +2496,7 @@ async function runLayoutAction(path) {
const out = await apiPost(path, {
payload: state.model,
options: compileOptions({
- respect_locks: true
+ respect_locks: path.includes("/tidy")
})
});
@@ -2768,7 +2770,6 @@ function setupEvents() {
pushHistory("rotate");
const current = Number(inst.placement.rotation ?? 0);
inst.placement.rotation = ((Math.round(current / 90) * 90 + 90) % 360 + 360) % 360;
- inst.placement.locked = true;
renderSelected();
el.jsonFeedback.textContent = "Component rotated.";
queueCompile(true, "rotate");
@@ -3416,7 +3417,6 @@ function setupEvents() {
if (inst) {
inst.placement.x = pos.x;
inst.placement.y = pos.y;
- inst.placement.locked = true;
}
}
await compileModel(state.model, { source: "drag", keepView: true, preservePlacement: true });
@@ -3465,7 +3465,6 @@ function setupEvents() {
}
const current = Number(inst.placement.rotation ?? 0);
inst.placement.rotation = ((Math.round(current / 90) * 90 + 90) % 360 + 360) % 360;
- inst.placement.locked = true;
}
compileModel(state.model, { source: "rotate", keepView: true, preservePlacement: true });
evt.preventDefault();
@@ -3739,6 +3738,26 @@ function setupEvents() {
await runLayoutAction("/layout/tidy");
});
+ el.unlockAllBtn?.addEventListener("click", async () => {
+ if (!state.model) {
+ return;
+ }
+ pushHistory("unlock-all");
+ let changed = 0;
+ for (const inst of state.model.instances ?? []) {
+ if (inst?.placement?.locked) {
+ inst.placement.locked = false;
+ changed += 1;
+ }
+ }
+ if (!changed) {
+ el.jsonFeedback.textContent = "All components are already unlocked.";
+ return;
+ }
+ el.jsonFeedback.textContent = `Unlocked ${changed} component${changed === 1 ? "" : "s"}.`;
+ await compileModel(state.model, { keepView: true, source: "unlock-all", preservePlacement: true });
+ });
+
el.themeToggleBtn?.addEventListener("click", () => {
applyTheme(state.theme === "dark" ? "light" : "dark");
});
diff --git a/frontend/index.html b/frontend/index.html
index 9757b63..c00b494 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -20,6 +20,7 @@
+