refactor(frontend): extract keybinding utilities

This commit is contained in:
Dariusz L
2026-08-02 13:52:46 +02:00
parent 06270d4f5d
commit 25bde5f58b
3 changed files with 54 additions and 84 deletions
+5 -39
View File
@@ -1,44 +1,10 @@
import fs from 'node:fs';
import path from 'node:path';
import test from 'node:test';
import assert from 'node:assert/strict';
const projectRoot = path.resolve(import.meta.dirname, '..');
const modelResolverSource = fs.readFileSync(
path.join(projectRoot, 'web/resolver/model_resolver.js'),
'utf8'
);
function extractFunction(source, functionName) {
const signature = new RegExp(`\\nfunction ${functionName}\\s*\\(`);
const match = signature.exec(source);
assert.ok(match, `Could not find ${functionName}`);
const parenStart = source.indexOf('(', match.index);
let parenDepth = 0;
let parenEnd = -1;
for (let i = parenStart; i < source.length; i += 1) {
if (source[i] === '(') parenDepth += 1;
if (source[i] === ')') parenDepth -= 1;
if (parenDepth === 0) {
parenEnd = i;
break;
}
}
const braceStart = source.indexOf('{', parenEnd);
let braceDepth = 0;
for (let i = braceStart; i < source.length; i += 1) {
if (source[i] === '{') braceDepth += 1;
if (source[i] === '}') braceDepth -= 1;
if (braceDepth === 0) {
return `function ${functionName}${source.slice(parenStart, parenEnd + 1)} ${source.slice(braceStart, i + 1)}`;
}
}
throw new Error(`Could not parse ${functionName}`);
}
const serializeKeybindingCombo = eval(`(${extractFunction(modelResolverSource, 'serializeKeybindingCombo')})`);
const keybindingsEqual = eval(`(${extractFunction(modelResolverSource, 'keybindingsEqual')})`);
const getComboLabel = eval(`(${extractFunction(modelResolverSource, 'getComboLabel')})`);
import {
serializeKeybindingCombo,
keybindingsEqual,
getComboLabel,
} from '../web/resolver/utils/keybinding_utils.js';
test('keybinding serialization is stable for equivalent combos', () => {
assert.equal(serializeKeybindingCombo({ key: 'k', ctrl: true, shift: false }), 'K:true:false:false');
+5 -45
View File
@@ -6,6 +6,11 @@ import { logger as frontendLogger } from "../log_system/logger.js";
import { loadStylesWhenNeeded } from "../utils/css_loader.js";
import { ResolverManagerDialog } from "./resolver_dialog.js";
import { showNotification } from "../utils/notification_utils.js";
import {
serializeKeybindingCombo,
keybindingsEqual,
getComboLabel,
} from "./utils/keybinding_utils.js";
import {
buildModelResolverNodeMenu,
getImmediateModelsForNode,
@@ -52,51 +57,6 @@ function getKeybindingSetting(id) {
}
}
function serializeKeybindingCombo(combo = {}) {
return [
String(combo.key || "").toUpperCase(),
String(Boolean(combo.ctrl)),
String(Boolean(combo.alt)),
String(Boolean(combo.shift)),
].join(":");
}
function keybindingsEqual(left, right) {
return Boolean(
left
&& right
&& left.commandId === right.commandId
&& (left.targetElementId || "") === (right.targetElementId || "")
&& serializeKeybindingCombo(left.combo) === serializeKeybindingCombo(right.combo)
);
}
function getComboLabel(combo = {}) {
const parts = [];
if (combo.ctrl) parts.push("Ctrl");
if (combo.alt) parts.push("Alt");
if (combo.shift) parts.push("Shift");
const keyLabels = {
" ": "Space",
ArrowUp: "Up",
ArrowDown: "Down",
ArrowLeft: "Left",
ArrowRight: "Right",
Backspace: "Backspace",
Delete: "Delete",
Enter: "Enter",
Escape: "Esc",
Tab: "Tab",
};
const key = String(combo.key || "").trim();
if (key) {
parts.push(keyLabels[key] || (key.length === 1 ? key.toUpperCase() : key));
}
return parts.join("+");
}
function applyStoredFrontendLoggingPreference() {
const stored = localStorage.getItem('ModelResolver.frontendLogsEnabled');
if (stored !== null) {
+44
View File
@@ -0,0 +1,44 @@
export function serializeKeybindingCombo(combo = {}) {
return [
String(combo.key || "").toUpperCase(),
String(Boolean(combo.ctrl)),
String(Boolean(combo.alt)),
String(Boolean(combo.shift)),
].join(":");
}
export function keybindingsEqual(left, right) {
return Boolean(
left
&& right
&& left.commandId === right.commandId
&& (left.targetElementId || "") === (right.targetElementId || "")
&& serializeKeybindingCombo(left.combo) === serializeKeybindingCombo(right.combo)
);
}
export function getComboLabel(combo = {}) {
const parts = [];
if (combo.ctrl) parts.push("Ctrl");
if (combo.alt) parts.push("Alt");
if (combo.shift) parts.push("Shift");
const keyLabels = {
" ": "Space",
ArrowUp: "Up",
ArrowDown: "Down",
ArrowLeft: "Left",
ArrowRight: "Right",
Backspace: "Backspace",
Delete: "Delete",
Enter: "Enter",
Escape: "Esc",
Tab: "Tab",
};
const key = String(combo.key || "").trim();
if (key) {
parts.push(keyLabels[key] || (key.length === 1 ? key.toUpperCase() : key));
}
return parts.join("+");
}