mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 00:55:16 -07:00
a9f66329ce
- subtitleStyle.css / subtitleStyle.secondary.css replace flat style fields in the settings window - ankiConnect.nPlusOne.enabled gates known-word cache independently of knownWords.highlightEnabled - Settings search now covers all categories, narrows on multi-word terms, and hides editor-owned fields - Default note-type picker to Kiku then Lapis; rename isLapis.sentenceCardModel default to "Lapis"
163 lines
5.1 KiB
TypeScript
163 lines
5.1 KiB
TypeScript
import { DEFAULT_KEYBINDINGS } from '../config/definitions/shared';
|
|
import type { ConfigSettingsField } from '../types/settings';
|
|
import {
|
|
buildMpvKeybindingConfigValue,
|
|
createMpvKeybindingRows,
|
|
keyboardEventToConfigKey,
|
|
parseMpvCommandText,
|
|
type KeyInputMode,
|
|
type MpvKeybindingRow,
|
|
} from './key-input';
|
|
import type { SettingsControlContext } from './settings-control-context';
|
|
import { createElement } from './settings-control-dom';
|
|
|
|
let activeKeyLearningStop: (() => void) | null = null;
|
|
let requestRender = (): void => undefined;
|
|
|
|
export function configureKeybindingControls(options: { requestRender: () => void }): void {
|
|
requestRender = options.requestRender;
|
|
}
|
|
|
|
function startKeyLearning(
|
|
button: HTMLButtonElement,
|
|
mode: KeyInputMode,
|
|
onValue: (value: string) => void,
|
|
): void {
|
|
activeKeyLearningStop?.();
|
|
const previousText = button.textContent ?? '';
|
|
button.textContent = 'Press Keys...';
|
|
button.classList.add('learning');
|
|
let onKeyDown: (event: KeyboardEvent) => void;
|
|
let onBlur: () => void;
|
|
let onMouseDown: (event: MouseEvent) => void;
|
|
|
|
const stop = (): void => {
|
|
window.removeEventListener('keydown', onKeyDown, true);
|
|
window.removeEventListener('blur', onBlur, true);
|
|
window.removeEventListener('mousedown', onMouseDown, true);
|
|
button.classList.remove('learning');
|
|
if (button.textContent === 'Press Keys...') {
|
|
button.textContent = previousText;
|
|
}
|
|
if (activeKeyLearningStop === stop) {
|
|
activeKeyLearningStop = null;
|
|
}
|
|
};
|
|
|
|
onKeyDown = (event: KeyboardEvent): void => {
|
|
if (event.key === 'Escape') {
|
|
stop();
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
const next = keyboardEventToConfigKey(event, mode);
|
|
if (!next) return;
|
|
stop();
|
|
onValue(next);
|
|
};
|
|
onBlur = (): void => stop();
|
|
onMouseDown = (event: MouseEvent): void => {
|
|
if (event.target !== button) {
|
|
stop();
|
|
}
|
|
};
|
|
|
|
window.addEventListener('keydown', onKeyDown, true);
|
|
window.addEventListener('blur', onBlur, true);
|
|
window.addEventListener('mousedown', onMouseDown, true);
|
|
activeKeyLearningStop = stop;
|
|
}
|
|
|
|
function renderKeyLearnButton(
|
|
value: string,
|
|
mode: KeyInputMode,
|
|
onValue: (value: string) => void,
|
|
): HTMLButtonElement {
|
|
const button = createElement('button', 'key-learn-button') as HTMLButtonElement;
|
|
button.type = 'button';
|
|
button.textContent = value || 'Unset';
|
|
button.addEventListener('click', () =>
|
|
startKeyLearning(button, mode, (next) => {
|
|
button.textContent = next;
|
|
onValue(next);
|
|
}),
|
|
);
|
|
return button;
|
|
}
|
|
|
|
export function renderKeyboardInput(
|
|
context: SettingsControlContext,
|
|
field: ConfigSettingsField,
|
|
mode: KeyInputMode,
|
|
): HTMLElement {
|
|
const value = context.valueForField(field);
|
|
return renderKeyLearnButton(typeof value === 'string' ? value : '', mode, (next) => {
|
|
context.updateDraft(field.configPath, next);
|
|
});
|
|
}
|
|
|
|
function applyMpvRows(
|
|
context: SettingsControlContext,
|
|
field: ConfigSettingsField,
|
|
rows: MpvKeybindingRow[],
|
|
): void {
|
|
context.updateDraft(field.configPath, buildMpvKeybindingConfigValue(DEFAULT_KEYBINDINGS, rows));
|
|
}
|
|
|
|
export function renderMpvKeybindingsInput(
|
|
context: SettingsControlContext,
|
|
field: ConfigSettingsField,
|
|
): HTMLElement {
|
|
const rows = createMpvKeybindingRows(DEFAULT_KEYBINDINGS, context.valueForField(field));
|
|
const container = createElement('div', 'keybinding-editor');
|
|
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row = rows[i]!;
|
|
const item = createElement('div', 'keybinding-row');
|
|
const keyButton = renderKeyLearnButton(row.key, 'dom-code', (next) => {
|
|
row.key = next;
|
|
applyMpvRows(context, field, rows);
|
|
});
|
|
const command = createElement('input', 'config-input mono-input') as HTMLInputElement;
|
|
command.type = 'text';
|
|
command.value = row.commandText;
|
|
command.placeholder = '["cycle","pause"]';
|
|
command.addEventListener('input', () => {
|
|
const parsed = parseMpvCommandText(command.value);
|
|
if (parsed === undefined) {
|
|
command.classList.add('invalid');
|
|
context.setFieldError(field.configPath, 'Invalid MPV command JSON');
|
|
return;
|
|
}
|
|
command.classList.remove('invalid');
|
|
context.setFieldError(field.configPath, null);
|
|
row.command = parsed;
|
|
row.commandText = command.value;
|
|
applyMpvRows(context, field, rows);
|
|
});
|
|
const removeButton = createElement('button', 'reset-button icon-button') as HTMLButtonElement;
|
|
removeButton.type = 'button';
|
|
removeButton.textContent = 'Remove';
|
|
removeButton.addEventListener('click', () => {
|
|
rows.splice(i, 1);
|
|
applyMpvRows(context, field, rows);
|
|
requestRender();
|
|
});
|
|
item.append(keyButton, command, removeButton);
|
|
container.append(item);
|
|
}
|
|
|
|
const addButton = createElement('button', 'secondary-button compact-button') as HTMLButtonElement;
|
|
addButton.type = 'button';
|
|
addButton.textContent = 'Add Binding';
|
|
addButton.addEventListener('click', () => {
|
|
rows.push({ defaultKey: '', key: '', command: null, commandText: '', isDefault: false });
|
|
applyMpvRows(context, field, rows);
|
|
requestRender();
|
|
});
|
|
container.append(addButton);
|
|
|
|
return container;
|
|
}
|