71c / Canvas Unlimited Quiz Helper

// ==UserScript==
// @name         Canvas Unlimited Quiz Helper
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  easily finish unlimited attempt quizzes on Canvas
// @author       Alon Jacobson
// @include      https://canvas.tufts.edu/courses/*/quizzes/*
// @icon         https://www.google.com/s2/favicons?domain=bkmks.com
// @license      MIT
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

function questionEltToData(e) {
    const header = e.querySelector(".header").children[0];
    const isIncorrect = header.children.length >= 1;
    const questionName = isIncorrect ? header.childNodes[1].nodeValue :
                                       header.innerText;
    const id = e.querySelector(".display_question").id;
    const questionDesc = e.querySelector(".question_text").innerText;
    const answerElts = [...e.querySelector(".answers_wrapper").querySelectorAll(".select_answer")];

    const answers = answerElts.map(answerElt => ({
        desc: answerElt.innerText.trim(),
        selected: answerElt.children[0].checked
    }));

    return {
        isIncorrect: isIncorrect,
        name: questionName,
        desc: questionDesc,
        answers: answers,
        id: id
    };
}

function fillInAnswers(answersData) {
    for (const info of answersData) {
        const e = document.getElementById(info.id);
        const selectedAnswersDescs = info.answers.filter(x => x.selected)
                                                 .map(x => x.desc)
        const answersElts = e.querySelectorAll(".answer");
        for (const answerElt of answersElts) {
            if (selectedAnswersDescs.includes(answerElt.innerText)) {
                if (info.isIncorrect)
                    answerElt.querySelector("input").checked = true;
                else
                    answerElt.querySelector("input").click();
            }
        }

        const flagElt = e.querySelector(".flag_question");
        const flagIsChecked = flagElt.getAttribute("aria-checked") == "true";

        if (info.isIncorrect !== flagIsChecked) {
            flagElt.click();
        }
    }
}

(function() {
    const re = /(\d+)\/quizzes\/(\d+)/;
    const matches = window.location.href.match(re);
    if (matches === null) return;
    const answersID = "answersData" + matches[0] + "_" + matches[1];

    const afterTakingQuiz = document.querySelector(".quiz_score") !== null;

    if (afterTakingQuiz) { // after quiz taken
        const canTakeAgain = document.getElementById("take_quiz_link") !== null;
        const questionsElts = [...document.querySelectorAll(".quiz_sortable")];
        if (questionsElts.length > 0) { //canTakeAgain &&
            console.log("can get data from previous attempt");
            const button = document.createElement('button');
            button.onclick = function() {
                const answersData = questionsElts.map(questionEltToData);
                const questionsDataString = JSON.stringify(answersData);
                GM_setValue(answersID, questionsDataString);
            };
            button.innerHTML = 'save answers';
            document.querySelector('.quiz-header').appendChild(button);
        }
    } else { // taking the quiz
        const questionsElts = [...document.querySelectorAll(".quiz_sortable")];
        const answersDataString = GM_getValue(answersID);
        if (questionsElts.length > 0 ) {///&& answersDataString !== undefined
            const answersData = JSON.parse(answersDataString);
            const button = document.createElement('button');
            button.onclick = function() {
                fillInAnswers(answersData);
            };
            button.innerHTML = 'populate answers';
            document.querySelector('.quiz-header').appendChild(button);
        }
    }
})();