Use keyboard on cards.ucalgary.ca: numbers to select, Enter to submit/next/review, ~ to clear, supports all question types
目前為
// ==UserScript==
// @name UCalgary Card Keyboard Shortcuts
// @version 2.2
// @description Use keyboard on cards.ucalgary.ca: numbers to select, Enter to submit/next/review, ~ to clear, supports all question types
// @match https://cards.ucalgary.ca/card/*
// @grant none
// @namespace https://greasyfork.org/users/1331386
// ==/UserScript==
(function () {
'use strict';
function addKeyboardHints() {
const forms = document.querySelectorAll('form.question');
forms.forEach(form => {
const labels = form.querySelectorAll('.option label');
labels.forEach((label, idx) => {
if (!label.dataset.hinted) {
const numberHint = `<span style="font-weight: 600; margin-right: 4px;">${idx + 1}.</span>`;
label.innerHTML = numberHint + label.innerHTML;
label.dataset.hinted = 'true';
}
});
});
}
function clearSelections() {
document.querySelectorAll('form.question input[type="radio"], form.question input[type="checkbox"]')
.forEach(input => input.checked = false);
}
function getOptionIndex(e) {
const keyMap = {
Digit1: 0,
Digit2: 1,
Digit3: 2,
Digit4: 3,
Digit5: 4,
Digit6: 5,
Digit7: 6,
Digit8: 7,
Digit9: 8,
Digit0: 9,
};
if (e.code in keyMap) {
const baseIndex = keyMap[e.code];
return e.shiftKey ? baseIndex + 10 : baseIndex;
}
return null;
}
function handleEnterKey() {
const submitBtn = document.querySelector('form.question .submit button');
const nextBtn = document.querySelector('#next');
const reviewBtn = document.querySelector('div.actions span.review-buttons a.save');
if (submitBtn && submitBtn.offsetParent !== null) {
submitBtn.click();
} else if (nextBtn && nextBtn.offsetParent !== null) {
nextBtn.click();
} else if (reviewBtn && reviewBtn.offsetParent !== null) {
reviewBtn.click();
}
}
document.addEventListener('keydown', function (e) {
const radios = document.querySelectorAll('form.question input[type="radio"]');
const checkboxes = document.querySelectorAll('form.question input[type="checkbox"]');
const index = getOptionIndex(e);
if (index !== null) {
if (radios[index]) {
radios[index].checked = true;
radios[index].scrollIntoView({ behavior: "smooth", block: "center" });
}
if (checkboxes[index]) {
checkboxes[index].checked = !checkboxes[index].checked;
checkboxes[index].scrollIntoView({ behavior: "smooth", block: "center" });
}
return;
}
if (e.key === 'Enter' || e.key === ' ') {
handleEnterKey();
}
if (e.key === '~') {
clearSelections();
}
});
window.addEventListener('load', addKeyboardHints);
document.addEventListener('DOMContentLoaded', addKeyboardHints);
const observer = new MutationObserver(addKeyboardHints);
observer.observe(document.body, { childList: true, subtree: true });
})();