Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # docs/architecture/frontend.md
111 lines
4.1 KiB
JavaScript
111 lines
4.1 KiB
JavaScript
// Shift+B ("B" for browser). Not B alone: comfyui-browser toggles its own window on a plain b
|
|
// and has no setting for it. Not Ctrl+Shift+M: Chrome and Edge take it (switch profile).
|
|
export const DEFAULT_BROWSER_SHORTCUT = Object.freeze({
|
|
key: 'b',
|
|
shift: true
|
|
});
|
|
|
|
export function formatKeyCombo(combo) {
|
|
if (!combo) return '';
|
|
if (typeof combo.getKeySequences === 'function') {
|
|
return combo.getKeySequences().join(' + ');
|
|
}
|
|
|
|
const keys = [];
|
|
if (combo.ctrl || combo.meta) keys.push('Ctrl');
|
|
if (combo.alt) keys.push('Alt');
|
|
if (combo.shift) keys.push('Shift');
|
|
if (combo.key) {
|
|
keys.push(combo.key.length === 1 ? combo.key.toUpperCase() : combo.key);
|
|
}
|
|
return keys.join(' + ');
|
|
}
|
|
|
|
function getCommand(app, commandId) {
|
|
return app.extensionManager?.command?.commands?.find((command) => command.id === commandId);
|
|
}
|
|
|
|
function waitForElement(selector, timeout = 1500) {
|
|
return new Promise((resolve) => {
|
|
const existing = document.querySelector(selector);
|
|
if (existing) {
|
|
resolve(existing);
|
|
return;
|
|
}
|
|
|
|
const observer = new MutationObserver(() => {
|
|
const element = document.querySelector(selector);
|
|
if (!element) return;
|
|
observer.disconnect();
|
|
clearTimeout(timer);
|
|
resolve(element);
|
|
});
|
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
const timer = setTimeout(() => {
|
|
observer.disconnect();
|
|
resolve(null);
|
|
}, timeout);
|
|
});
|
|
}
|
|
|
|
function setInputValue(input, value) {
|
|
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;
|
|
if (setter) setter.call(input, value);
|
|
else input.value = value;
|
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}
|
|
|
|
export async function openNativeKeybindingEditor(commandId) {
|
|
const settingsDialog = document.querySelector('[data-testid="settings-dialog"]');
|
|
const keybindingNav = settingsDialog?.querySelector('[data-nav-id="keybinding"]');
|
|
if (!(keybindingNav instanceof HTMLElement)) return false;
|
|
|
|
keybindingNav.click();
|
|
const searchInput = await waitForElement('#keybinding-panel-header input');
|
|
if (!(searchInput instanceof HTMLInputElement)) return false;
|
|
|
|
setInputValue(searchInput, commandId);
|
|
const commandTitle = await waitForElement(`.keybinding-panel [title="${CSS.escape(commandId)}"]`);
|
|
const commandRow = commandTitle?.closest('tr');
|
|
if (!commandRow) return false;
|
|
|
|
const actionButtons = commandRow.querySelectorAll('.actions button');
|
|
const bindingCellText = commandRow.children[1]?.textContent?.trim();
|
|
const canOpenRecorderDirectly = actionButtons.length >= 4 || bindingCellText === '-';
|
|
if (canOpenRecorderDirectly && actionButtons[0] instanceof HTMLButtonElement) {
|
|
actionButtons[0].click();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function createShortcutSettingControl({ app, commandId, translate, settingLabelKey = 'mainShortcutSetting' }) {
|
|
const container = document.createElement('div');
|
|
container.className = 'anomalous-shortcut-setting';
|
|
|
|
const current = document.createElement('kbd');
|
|
current.className = 'anomalous-shortcut-current';
|
|
const combo = getCommand(app, commandId)?.keybinding?.combo;
|
|
current.textContent = formatKeyCombo(combo) || translate('mainShortcutUnassigned');
|
|
|
|
const customize = document.createElement('button');
|
|
customize.type = 'button';
|
|
customize.className = 'anomalous-shortcut-customize';
|
|
customize.textContent = translate('mainShortcutCustomize');
|
|
customize.addEventListener('click', async () => {
|
|
customize.disabled = true;
|
|
const opened = await openNativeKeybindingEditor(commandId);
|
|
customize.disabled = false;
|
|
if (!opened) {
|
|
app.extensionManager?.toast?.add?.({
|
|
severity: 'warn',
|
|
summary: translate(settingLabelKey),
|
|
detail: translate('mainShortcutOpenFailed'),
|
|
life: 3500
|
|
});
|
|
}
|
|
});
|
|
|
|
container.append(current, customize);
|
|
return container;
|
|
}
|