aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/dashboard/dashboard.html
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-09 01:32:24 +0000
committertv <tv@krebsco.de>2026-11-09 02:33:13 +0100
commit5f2ea365cfd09d54b5ac8af3e5146e6d881c7554 (patch)
tree8cf6db9928d432535f0aa96ff2bad75f053c8776 /src/api/dashboard/dashboard.html
parentdee32092163bddddab11d6d6c282851643a75acb (diff)
dashboard: the document box edited from its menus alone
With the entries' menus (1238), editing had three ways in: the double-click, the `+` on a map's or list's row, and the menu. The double-click and the `+` go; the menu does all of it. The title, which stands for the root (its row isn't shown), now takes the right-click too: its menu adds a key at the top level.
Diffstat (limited to 'src/api/dashboard/dashboard.html')
-rw-r--r--src/api/dashboard/dashboard.html64
1 files changed, 19 insertions, 45 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html
index 6df3300..18c7ab1 100644
--- a/src/api/dashboard/dashboard.html
+++ b/src/api/dashboard/dashboard.html
@@ -76,7 +76,6 @@
section.collapsed { align-self: start; }
section.collapsed h2 { margin: 0; }
section.collapsed h2 .toggle { display: none; }
- section.collapsed h2 button.add { display: none; }
/* A choice beside a box's title (the console's filter). */
section h2 label.choice { font-size: 12px; text-transform: none; letter-spacing: 0;
margin-left: 1em; cursor: pointer; }
@@ -274,13 +273,9 @@
max-height: 20em; overflow: auto; }
.note { color: var(--muted); font-style: italic; }
.error { color: var(--bad); }
- .tree button.add, #document-head button.add { font: inherit; line-height: 1; padding: 0 4px; margin-left: 4px;
- color: var(--muted); background: none; border: 1px solid var(--line); border-radius: 3px;
- cursor: pointer; }
- .tree button.add:hover, #document-head button.add:hover { color: var(--fg); border-color: var(--muted); }
.tree .nested { padding-left: 1.1em; }
- /* The store's root is the box: its keys listed at the top level, its size and its "+"
- in the title (`#document-head`). */
+ /* The store's root is the box: its keys listed at the top level, its size in the
+ title (`#document-head`), whose menu is the root's. */
#document > details.root { padding-left: 0; }
#document > details.root > summary { display: none; }
section h2 .count { text-transform: none; letter-spacing: 0; font-weight: normal;
@@ -1612,7 +1607,7 @@ async function readStore(path, shallow) {
const EMPTY = { map: "{}", list: "[]", text: "\"\"" };
const EMPTY_VALUE = { map: () => ({}), list: () => [], text: () => "" };
-// --- Editing: a double click on an entry turns it into a field holding its contents;
+// --- Editing: `Edit value` in an entry's menu turns it into a field holding its contents;
// saved with PUT /store/<path> (the whole value, objects too) ---
// A string is edited as text (sent as text/plain), anything else as JSON; "JSON"
// switches. `done(saved, response)` when saved or cancelled.
@@ -1746,21 +1741,10 @@ const editing = element => element.querySelector(".editor") !== null;
// Adding to a map (a key and its value, PUT /store/<path>/<key>) or a list (an index
// and the value, POST /store/<path>/<index>: the items from there on move up; -1 is the
-// end), without writing it whole: a "+" on the row, the field below it. `known()`: a
-// map's keys as last read, so an existing one isn't overwritten.
-function addButton(kind, path, known, place) {
- const button = el("button", { type: "button", class: "add",
- title: kind === "map" ? "Add a key" : "Insert an item" }, "+");
- button.addEventListener("click", event => {
- // Not a click on the row: it would open or close it.
- event.preventDefault();
- event.stopPropagation();
- adding(kind, path, known, place, "-1");
- });
- return button;
-}
-// The field for adding to `path` (`addButton`), below its row: a list's index as
-// `index` has it at first ("-1": at the end; "": asked for).
+// end), without writing it whole. `known()`: a map's keys as last read, so an existing
+// one isn't overwritten.
+// The field for adding to `path` (from its menu, `entryItems`), below its row: a list's
+// index as `index` has it at first ("-1": at the end; "": asked for).
function adding(kind, path, known, place, index) {
const map = kind === "map";
{
@@ -1798,7 +1782,7 @@ function adding(kind, path, known, place, index) {
// --- An entry's menu (right-click, or a finger held on it): edit its value, rename its
// key (a map's), add to it (a map: a key; a list: an item at the end, or at an index).
-// Each as the double-click and the "+" do. ---
+// Each in a field below its row. ---
function entryMenu(x, y, items) {
const menu = document.getElementById("entry-menu");
menu.replaceChildren(...items.map(([label, act]) => {
@@ -1938,7 +1922,7 @@ function editableLeaf(key, shown, value, path) {
...(glosses ? glossed(aliasOf(key)) : []), ": "), shown,
...(glosses ? glossed(gloss(key, value)) : []));
if (!editable(path)) return leaf;
- leaf.title = "Double-click to edit, right-click for more";
+ leaf.title = "Right-click (or hold a finger on it) for its menu";
leaf.edit = () => {
if (editing(leaf)) return;
window.getSelection().removeAllRanges();
@@ -1948,10 +1932,6 @@ function editableLeaf(key, shown, value, path) {
edited(path, saved);
}));
};
- leaf.addEventListener("dblclick", event => {
- event.preventDefault();
- leaf.edit();
- });
return leaf;
}
@@ -1975,10 +1955,9 @@ function glow(entry) {
function documentEntry(key, summary, path, parentKind = null, siblings = () => []) {
if (summary.size === 0 && summary.type in EMPTY) {
const leaf = editableLeaf(key, EMPTY[summary.type], EMPTY_VALUE[summary.type](), path);
- // An empty map or list takes its first entry here: "+" on its row, the field below.
+ // An empty map or list takes its first entry here: from its menu, the field below.
if ((summary.type === "map" || summary.type === "list") && editable(path)) {
const below = el("div", { class: "nested" });
- leaf.append(" ", addButton(summary.type, path, () => [], () => below));
withMenu(leaf, () => entryItems({ path, kind: summary.type, parentKind, siblings,
row: leaf, edit: leaf.edit, known: () => [], place: () => below }));
return el("div", {}, leaf, below);
@@ -2000,15 +1979,10 @@ function documentEntry(key, summary, path, parentKind = null, siblings = () => [
const head = el("summary", {}, el("span", { class: "key" }, key),
...(glossedPath(path) ? glossed(aliasOf(key)) : []), " ", described);
details.append(head);
- // A double click edits the whole of it: read, then shown in a field.
+ // Edited as a whole (from its menu): read, then shown in a field.
let edit = null;
if (editable(path)) {
- head.title = "Double-click to edit, right-click for more";
- head.addEventListener("mousedown", event => { if (event.detail > 1) event.preventDefault(); });
- head.addEventListener("dblclick", event => {
- event.preventDefault();
- edit();
- });
+ head.title = "Right-click (or hold a finger on it) for its menu";
edit = async () => {
if (details.querySelector(":scope > .editor:not(.renamer)")) return;
let value;
@@ -2044,11 +2018,9 @@ function documentEntry(key, summary, path, parentKind = null, siblings = () => [
details.open = true;
return { prepend: form => head.after(form), querySelector: q => details.querySelector(":scope > " + q) };
};
- if (writable) {
- head.append(" ", addButton(summary.type, path, () => [...children.keys()], place));
- }
- withMenu(head, () => entryItems({ path, kind: summary.type, parentKind, siblings, row: head,
- edit, known: () => [...children.keys()], place: writable ? place : null }));
+ details.menuItems = () => entryItems({ path, kind: summary.type, parentKind, siblings,
+ row: head, edit, known: () => [...children.keys()], place: writable ? place : null });
+ withMenu(head, details.menuItems);
let read = false;
// Read once at least: what's new or changed from then on breathes (`glow`).
let filled = false;
@@ -2132,13 +2104,15 @@ function documentChanged(change) {
if (change.all || change.paths.some(path => related(path, branch.path))) branch.refresh();
}
}
-// The store's root, always open: its keys are the box's top level, and its size and its
-// "+" (everything its row has but its key) go into the title.
+// The store's root, always open: its keys are the box's top level, and its size
+// (everything its row has but its key) goes into the title.
const documentRoot = documentEntry("store", { type: "map", size: "…" }, []);
documentRoot.classList.add("root");
documentRoot.open = true;
document.getElementById("document-head").append(
...[...documentRoot.querySelector(":scope > summary").childNodes].slice(1));
+// The title stands for the root: its menu adds a key at the top level.
+withMenu(document.querySelector("#document-box > h2"), documentRoot.menuItems);
document.getElementById("document").replaceChildren(documentRoot);
// A box is busy while text in it is selected: drawing it anew would lose the selection,