Stealthily highlights correct Canvas quiz answers with a faint right-edge shadow on hover only. Won’t steal focus or trigger LMS cursor alerts. API-based & unobtrusive UX by design. Fully self-contained & auto-loaded on quiz pages only.
当前为
// ==UserScript==
// @name Canvas Quiz Answer Identifier (Subtle Shadow + Edge Hover)
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Stealthily highlights correct Canvas quiz answers with a faint right-edge shadow on hover only. Won’t steal focus or trigger LMS cursor alerts. API-based & unobtrusive UX by design. Fully self-contained & auto-loaded on quiz pages only.
// @author You
// @match *://*.instructure.com/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
window.addEventListener('load', function () {
const texts = document.getElementsByClassName("text");
if (!texts.length) return;
let questions = [];
let optionsList = [];
// Step 1: Extract questions and options
for (let i = 0; i < texts.length; i++) {
const questionDiv = texts[i].querySelector("div:nth-of-type(2)");
const questionText = questionDiv?.innerText?.trim() || "";
const optionLabels = texts[i].getElementsByClassName("answer_label");
let optionsText = [];
for (let j = 0; j < optionLabels.length; j++) {
optionsText.push(optionLabels[j].innerText.trim());
}
questions.push(questionText);
optionsList.push(optionsText);
}
// Step 2: Send questions to the API and get answers
for (let i = 0; i < questions.length; i++) {
const payload = {
id: i,
question: questions[i],
options: optionsList[i].join(", "),
};
fetch("https://canvasquiz-new.uc.r.appspot.com/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
})
.then((res) => {
if (!res.ok) throw new Error("Network response error");
return res.json();
})
.then((data) => {
const correctAnswer = data.answer?.trim();
if (!correctAnswer) return;
const answerLabels = texts[i].getElementsByClassName("answer_label");
for (let j = 0; j < answerLabels.length; j++) {
const label = answerLabels[j];
const labelText = label.innerText.trim();
if (labelText === correctAnswer) {
label.style.position = "relative";
label.addEventListener("mouseenter", () => {
let shadowMarker = document.createElement("div");
shadowMarker.className = "hover-shadow-marker";
shadowMarker.style.position = "absolute";
shadowMarker.style.top = "50%";
shadowMarker.style.left = "100%"; // outside the label
shadowMarker.style.transform = "translateY(-50%) translateX(2px)";
shadowMarker.style.width = "8px";
shadowMarker.style.height = "20px";
shadowMarker.style.boxShadow = "0 0 6px rgba(0, 0, 0, 0.1)";
shadowMarker.style.borderRadius = "3px";
shadowMarker.style.pointerEvents = "none"; // don't interfere
label.appendChild(shadowMarker);
});
label.addEventListener("mouseleave", () => {
const marker = label.querySelector(".hover-shadow-marker");
if (marker) marker.remove();
});
}
}
})
.catch((err) => {
console.warn("Answer API error:", err);
});
}
});
})();