Cat-Printer/www/accessibility.js
2022-04-28 23:42:13 +08:00

114 lines
3.9 KiB
JavaScript

'use strict';
function isHidden(element) {
let parents = [element];
while (parents[0].parentElement)
parents.unshift(parents[0].parentElement);
return parents.some(e => {
let rect = e.getBoundingClientRect();
return (
e.classList.contains('hidden') ||
e.classList.contains('hard-hidden') ||
e.style.display == 'none' ||
rect.width == 0 || rect.height == 0 ||
// rect.x < 0 || rect.y < 0 ||
e.style.visibility == 'none' ||
e.style.opacity == '0'
);
});
}
function toLocaleKey(key) {
if (typeof i18n === 'undefined') return key;
const qwerty = '1234567890qwertyuiopasdfghjklzxcvbnm';
let keys, index;
if (key.length !== 1 ||
(keys = i18n('KeyboardLayout')) === 'KeyboardLayout' ||
(index = qwerty.indexOf(key)) === -1
) return key;
return keys[index];
}
function keyToLetter(key) {
const map = {
' ': 'SPACE',
',': 'COMMA',
'.': "DOT"
};
return map[key] || key;
}
function initKeyboardShortcuts() {
const layer = document.getElementById('keyboard-shortcuts-layer');
const dialog = document.getElementById('dialog');
const keys = 'qwertyuiopasdfghjklzxcvbnm';
let focusing = false, started = false;
let shortcuts = {};
let key, focus, inputs;
const mark_keys = () => {
let index;
if (dialog.classList.contains('hidden'))
inputs = Array.from(document.querySelectorAll('*[data-key]'));
else inputs = Array.from(document.querySelectorAll('#dialog *[data-key]'));
/** @type {{ [key: string]: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }} */
let keys2 = keys.split('');
shortcuts = {};
if (focusing) shortcuts = { ESC: focus };
else
for (let input of inputs) {
if (isHidden(input)) continue;
key = input.getAttribute('data-key');
if ((index = keys2.indexOf(key)) !== -1) keys2.splice(index, 1);
key = toLocaleKey(key || keys2.shift());
shortcuts[key] = input;
}
// Array.from(layer.children).forEach(e => e.remove());
for (let i = layer.children.length; i <= inputs.length; i++) {
let span = document.createElement('span');
layer.appendChild(span);
}
index = 0;
for (let key in shortcuts) {
let span = layer.children[index++];
let input = shortcuts[key];
let position = input.getBoundingClientRect();
let text = i18n(keyToLetter(key.toUpperCase()));
if (span.innerText !== text) span.innerText = text;
span.style.top = position.y + 'px';
span.style.left = position.x + 'px';
span.style.display = '';
}
for (let i = index; i < layer.children.length; i++) {
layer.children[i].style.display = 'none';
}
}
const start = () => setInterval(mark_keys, 1000);
const types_to_click = ['submit', 'file', 'checkbox', 'radio', 'A'];
document.body.addEventListener('keyup', (event) => {
key = event.key;
if (!started) {
if (key !== 'Tab') return;
mark_keys();
start();
started = true;
}
document.body.addEventListener('keyup', () =>
requestAnimationFrame(mark_keys)
, { once: true });
let input = shortcuts[key.toLocaleLowerCase()];
if (input) {
if (types_to_click.includes(input.type || input.tagName))
input.dispatchEvent(new MouseEvent(event.shiftKey ? 'contextmenu' : 'click'));
else {
input.focus();
focusing = true;
}
focus = input;
} else if (key === 'Escape' && focus) {
focus.blur();
focusing = !focusing;
}
});
}