Canvas Quiz Answer Identifier (Subtle Shadow + Edge Hover)

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.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==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);
                });
        }
    });
})();