您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enter/Shift-Enter for Next/Previous question, Up/Down for selecting multiple choice question, autoanswer
// ==UserScript== // @name Moodle Quiz Shorcuts // @namespace http://tampermonkey.net/ // @version 2025-04-04 // @description Enter/Shift-Enter for Next/Previous question, Up/Down for selecting multiple choice question, autoanswer // @author Lasu Shin // @match https://moodle.yerlan.top/mod/quiz/* // @icon https://moodle.yerlan.top/theme/image.php/boost/theme/1730285596/favicon // @grant none // ==/UserScript== // ENABLE DEV MODE IN CHROME/EDGE TO USE (firefox is safe:) //TODO //return prev btn without taking away enter functionality const prev_btn = document.getElementById('mod_quiz-prev-nav') const text_field = document.getElementsByClassName('form-control d-inline')[0] const options = document.getElementsByClassName('answer')[0] let radios = [] let multiple_choice = false let selected = null if (prev_btn) { //remove button bec sometimes it goes back when pressing enter for some reason prev_btn.remove() } // if the question is a text field answer, select it if (text_field) { text_field.select() } // if the question has multiple choices, add them to the list radios else if (options) { const isRadio = options.children[0]?.children[0]?.type === "radio"; multiple_choice = !isRadio; // Set multiple_choice to true if not radio for (let child of options.children) { // the radio button is index 0 for radios and 1 for multiple choice radios.push(isRadio ? child.children[0] : child.children[1]); } for (let i = 0; i < options.children.length; i++) { if (radios[i].checked) { selected = i break } } if (selected == null) { check(radios[0]) selected = 0 } } function check(radio) { if (multiple_choice) { radio.click() } else { radio.checked = true } } function normalize(text) { const words = text.split(' '); const startIndex = words.indexOf('Answer'); // If "Answer" is found, remove 3 words starting from it (Answer question X) if (startIndex !== -1) { return words .slice(0, startIndex) // Keep everything before "Answer" .concat(words.slice(startIndex + 3)) // Skip 3 words after "Answer" .join(' '); // Join back into a string } // If "Answer" isn't found, return the original text return text; } function saveQuizAnswers() { // Only run if we're on the correct page if (!window.location.href.startsWith('https://moodle.yerlan.top/mod/quiz/review.php')) { return; } const form = document.getElementById('region-main') .children[3] .children[1] .children[0] .children; if (form.length <=3) { return } const answers = {}; for (let question of form) { if (!question || !question.children[1]) { continue } const questionElements = question.children[1].children; const questionText = normalize(questionElements[0].children[2].textContent) const questionAnswer = questionElements[1].innerText.split(/: (.+)/)[1]; //only splits first ": " answers[questionText] = questionAnswer; } localStorage.setItem('lastReviewAnswers', JSON.stringify(answers)); alert('SAVED ANSWERS'); console.log(answers) } function handleNextButton() { const next_btn = document.getElementById('mod_quiz-next-nav') if (!next_btn) { console.log('Next button not found!') let submit_btn = document.getElementsByClassName('btn btn-primary')[0] let save_btn = document.querySelector('.btn.btn-primary[data-action=save]') if (!save_btn) { submit_btn.click() } else { save_btn.click() } } else { next_btn.click() } } function answer(savedAnswer) { if (text_field) { text_field.value = savedAnswer; } else if (radios.length > 0) { for (let radio of radios) { //if its a multiple choice, then the answer is the 3rd ([2]) element if its radios then [1]. substr 3 gets rid of the a. b. c. d. const answerText = radio.parentElement.children[multiple_choice ? 2 : 1].textContent.substr(3) if (answerText == savedAnswer) { radio.checked = true } else { radio.checked = false } } } handleNextButton() } function autoAnswer() { const questionElement = document.querySelector('.qtext'); if (questionElement) { // Check if there are saved answers in localStorage const savedAnswers = localStorage.getItem('lastReviewAnswers'); const answers = JSON.parse(savedAnswers) || {} let questionText = normalize(questionElement.textContent) let savedAnswer = answers[questionText]; if (!savedAnswer && options && options.textContent.includes(questionText)) { savedAnswer = questionText } if (savedAnswer) { answer(savedAnswer) } } } //MAIN PROGRAM autoAnswer() saveQuizAnswers() //focus on text field when returning to site from another tab document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { if (text_field) { text_field.select() } } }); // listen for keydown events (up, down, enter, backspace) document.addEventListener( "keydown", function( e ) { var keyCode = e.keyCode || e.which; // check whether its a multiple choice question before checking for up and down arrows for movement if (options) { // DOWN ARROW - SELLECT PREVIOUS OPTION if (keyCode === 40 || keyCode === 74) { radios[selected].checked = false selected = (selected + 1) % radios.length check(radios[selected]) // UP ARROW - SELECT NEXT OPTION } else if (keyCode === 38 || keyCode === 75) { radios[selected].checked = false selected = (selected + 3) % radios.length check(radios[selected]) } } // SHIFT + ENTER - GO BACK if (e.shiftKey && keyCode === 13) { window.history.back(); } // ENTER - NEXT QUESTION BUTTON else if (keyCode === 13) { handleNextButton(); } }, { capture: true });