您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Easily copy questions and answers from Udemy section quizzes
// ==UserScript== // @name Udemy - Copy from Section Quiz // @namespace http://tampermonkey.net/ // @version 1.1 // @description Easily copy questions and answers from Udemy section quizzes // @author John Farrell (https://www.johnfarrell.dev/) // @match https://www.udemy.com/course/* // @icon https://www.google.com/s2/favicons?sz=64&domain=udemy.com // ==/UserScript== (function () { "use strict"; // Select the node that will be observed for mutations const targetNode = document.querySelector("body"); // Options for the observer (which mutations to observe) const config = { attributes: true, childList: true, subtree: true }; const callback = function (mutationsList, observer) { // return if mutationList contains mutations caused by us adding buttons, otherwise get infinite recursion until browser crashes if ( mutationsList.find( (el) => el.addedNodes[0]?.id === "userscript-added-button-copy-question" || el.addedNodes[0]?.id === "userscript-added-button-copy-answer" ) ) { return; } const isQuizPage = document.querySelector( 'div[class^="compact-quiz-container--compact-quiz-container--"]' ) !== null; if (!isQuizPage) { return; } const progressionButton = document.querySelector( 'button[data-purpose="next-question-button"]' ); if (!progressionButton) { return; } const isQuestionStep = progressionButton.textContent === "Check answer"; const isAnswerStep = progressionButton.textContent === "Next" || progressionButton.textContent === "See results"; const quizFooter = document.querySelector( 'div[class^="curriculum-item-footer--flex-align-center--"] > div' ); if (isQuestionStep) { if (document.querySelector("#userscript-added-button-copy-question")) { return; } // remove the copy answer button added from isAnswerStep const copyAnswerButton = document.querySelector( "#userscript-added-button-copy-answer" ); copyAnswerButton?.parentNode.removeChild(copyAnswerButton); const questionElement = document.querySelector("#question-prompt"); const question = questionElement.innerText; const answerContainer = document.querySelector( 'ul[aria-labelledby="question-prompt"]' ); const answers = Array.from(answerContainer.querySelectorAll("li")).map( (el) => "\t• " + el.innerText ); const copyText = question + "\n\n" + answers.join("\n"); const copyQuestionButton = document.createElement("button"); copyQuestionButton.setAttribute( "id", "userscript-added-button-copy-question" ); copyQuestionButton.innerHTML = "Copy Question"; copyQuestionButton.addEventListener("click", () => { navigator.clipboard.writeText(copyText); }); quizFooter.append(copyQuestionButton); } else if (isAnswerStep) { if (document.querySelector("#userscript-added-button-copy-answer")) { return; } const answers = Array.from(document.querySelectorAll("input[type=radio]")) .filter((el) => el.checked) .map((el) => el.parentElement.textContent.trim()) .join("\n\n"); const additionalInfo = document .querySelector('div[class*="alert-banner-module--body--"]') ?.textContent.trim() || ""; const copyText = additionalInfo ? answers + "\n\n" + additionalInfo : answers; const copyAnswerButton = document.createElement("button"); copyAnswerButton.setAttribute( "id", "userscript-added-button-copy-answer" ); copyAnswerButton.innerHTML = "Copy Answer"; copyAnswerButton.addEventListener("click", () => { navigator.clipboard.writeText(copyText); }); quizFooter.append(copyAnswerButton); const nextQuestionSelector = 'button[data-purpose="next-question-button"]'; document .querySelector(nextQuestionSelector) .addEventListener("click", () => { // remove the copy question button when we click to go to the next question const copyQuestionButton = document.querySelector( "#userscript-added-button-copy-question" ); copyQuestionButton?.parentNode.removeChild(copyQuestionButton); const copyAnswerButton = document.querySelector( "#userscript-added-button-copy-answer" ); copyAnswerButton?.parentNode.removeChild(copyAnswerButton); }); } }; // Create an observer instance linked to the callback function const observer = new MutationObserver(callback); // Start observing the target node for configured mutations observer.observe(targetNode, config); })();