Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 332x 332x 835x 3377x 321x 298x 297x 1158x 295x 3022x 535x 1393x 1393x 29x 49x 49x 49x 68x 68x 68x 68x 49x 49x 49x 49x | /**
* The keys that windows answer while the machine is stopped. Each window declares a table of its
* keys, in the shape of the Shortcuts table: a row with a `key` runs the action its `run` names;
* a row with a `description` documents the keys its `combo` names, space separated, for Help, and
* a `label` puts them on the window's own line of keys. A row with no description is documented
* by another row naming its key.
*/
export class PanelKeys {
/** @param {import("./floating-panel.js").PanelArrangement} arrangement whose stacking decides between windows */
constructor(arrangement) {
this._arrangement = arrangement;
this._owners = [];
}
/**
* @param {object} owner
* @param {object[]} owner.table
* @param {Object<string, function(): void>} owner.actions what each row's `run` names
* @param {function(): boolean} owner.isLive whether its keys answer now
* @param {import("./floating-panel.js").FloatingPanel | null} owner.panel the window offering them, or null
* for keys that yield to any window's
*/
register(owner) {
this._owners.push(owner);
}
/**
* Runs what `key` is bound to by the live owner offering it whose window is in front.
* @returns {boolean} whether anything was bound to it
*/
press(key) {
const offering = this._owners.filter((owner) => owner.isLive() && owner.table.some((row) => row.key === key));
if (offering.length === 0) return false;
const front = this._arrangement.frontmost(offering.map((owner) => owner.panel));
const owner = offering.find((candidate) => candidate.panel === front);
owner.actions[owner.table.find((row) => row.key === key).run]();
return true;
}
}
const documented = (table) => table.filter((row) => row.description);
/** A window's line of keys, as "j/k move · b back". */
export function keyLine(table) {
return documented(table)
.filter((row) => row.label)
.map((row) => `${row.combo.replaceAll(" ", "/")} ${row.label}`)
.join(" · ");
}
/** Help's rows for `table`: each documented combo, its keys as key caps, and what they do. */
export function helpRows(table) {
return documented(table).map(({ combo, description }) => helpRow(combo.split(" "), description));
}
/** A row of Help: `keys` as key caps, and what they do. */
export function helpRow(keys, description) {
const row = document.createElement("tr");
const caps = document.createElement("td");
keys.forEach((key, index) => {
const cap = document.createElement("span");
cap.className = "key";
cap.textContent = key;
caps.append(...(index ? [" ", cap] : [cap]));
});
const what = document.createElement("td");
what.textContent = description;
row.append(caps, what);
return row;
}
|