anki/ts/editor/focusHandlers.ts

61 lines
1.9 KiB
TypeScript
Raw Normal View History

import type { EditingArea } from ".";
import { bridgeCommand } from "./lib";
import { enableButtons, disableButtons } from "./toolbar";
import { saveField } from "./changeTimer";
function isElementInViewport(element: Element): boolean {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
function caretToEnd(currentField: EditingArea): void {
const range = document.createRange();
range.selectNodeContents(currentField.editable);
range.collapse(false);
const selection = currentField.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
// For distinguishing focus by refocusing window from deliberate focus
let previousActiveElement: EditingArea | null = null;
export function onFocus(evt: FocusEvent): void {
const currentField = evt.currentTarget as EditingArea;
if (currentField === previousActiveElement) {
return;
}
currentField.focusEditable();
bridgeCommand(`focus:${currentField.ord}`);
enableButtons();
// do this twice so that there's no flicker on newer versions
caretToEnd(currentField);
// scroll if bottom of element off the screen
if (!isElementInViewport(currentField)) {
currentField.scrollIntoView(false /* alignToBottom */);
}
}
export function onBlur(evt: FocusEvent): void {
const currentField = evt.currentTarget as EditingArea;
if (currentField === previousActiveElement) {
// other widget or window focused; current field unchanged
saveField(currentField, "key");
previousActiveElement = currentField;
} else {
saveField(currentField, "blur");
disableButtons();
previousActiveElement = null;
}
}