GCN Training Auto-Navigation + Auto-Answer (Random Answers)

Auto-navigate slides & auto-answer assessments in GCN Training with single-line debug overlay and random answer selection

// ==UserScript==
// @name         GCN Training Auto-Navigation + Auto-Answer (Random Answers)
// @namespace    http://tampermonkey.net/
// @version      5.1
// @description  Auto-navigate slides & auto-answer assessments in GCN Training with single-line debug overlay and random answer selection
// @author       Cole Mistretta
// @match        https://site.gcntraining.com/user-admin/dashboard.html
// @match        https://site.gcntraining.com/t*/*
// @license GNU
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    ///////////////////////
    // Debug Panel Setup //
    ///////////////////////
    const panel = document.createElement('div');
    panel.id = "gcn-debug-panel";
    panel.innerHTML = `<div id="gcn-debug-text">GCN Auto-Navigation started.</div>`;
    document.body.appendChild(panel);

    const styles = document.createElement('style');
    styles.textContent = `
      #gcn-debug-panel {
        position: fixed;
        bottom: 10px;
        right: 10px;
        width: 300px;
        background: rgba(0,0,0,0.85);
        color: #00ffcc;
        font-family: monospace;
        font-size: 12px;
        border-radius: 8px;
        padding: 8px;
        z-index: 99999;
        text-align: center;
        box-shadow: 0 0 10px rgba(0,255,200,0.5);
      }
    `;
    document.head.appendChild(styles);

    function setDebug(text) {
        document.getElementById("gcn-debug-text").textContent = text;
        console.log(text);
    }

    //////////////////////////
    // Helper Functions     //
    //////////////////////////
    function clickNextStartButton() {
        // Check if we're on the dashboard
        if (!window.location.href.includes('dashboard.html')) {
            return false;
        }

        // FIRST PRIORITY: Look for Continue buttons (partially completed tutorials)
        const continueButtons = document.querySelectorAll('form.ud-continue button.ud-button');

        if (continueButtons.length > 0) {
            const firstContinueButton = continueButtons[0];
            const form = firstContinueButton.closest('form');
            const tutorialTitle = form ? form.querySelector('.tut-title')?.textContent : 'Unknown';

            setDebug(`Found ${continueButtons.length} tutorials to continue. Prioritizing: ${tutorialTitle}`);

            // Click the continue button
            firstContinueButton.click();

            return true;
        }

        // SECOND PRIORITY: Look for Start buttons (new tutorials) only if no Continue buttons
        const startButtons = document.querySelectorAll('form.ud-start button.ud-button');

        if (startButtons.length > 0) {
            const firstStartButton = startButtons[0];
            const form = firstStartButton.closest('form');
            const tutorialTitle = form ? form.querySelector('.tut-title')?.textContent : 'Unknown';

            setDebug(`No Continue buttons found. Found ${startButtons.length} tutorials to start. Starting: ${tutorialTitle}`);

            // Click the start button
            firstStartButton.click();

            return true;
        }

        setDebug("No Continue or Start buttons found on dashboard");
        return false;
    }

    function clickStartTutorialButton() {
        // Check if we're on a start page (pattern: /*/start)
        if (!window.location.pathname.endsWith('/start')) {
            return false;
        }

        // Look for the start tutorial button with multiple selector patterns
        const startTutorialSelectors = [
            'a.start-button img[alt="Start Tutorial"]',
            'a.start-button',
            'a[href*="/t"] img[alt="Start Tutorial"]',
            'a[href*="/t"]',
            '.start-button',
            'img[alt="Start Tutorial"]'
        ];

        let startButton = null;
        let usedSelector = "";

        for (const selector of startTutorialSelectors) {
            const element = document.querySelector(selector);
            if (element && element.offsetParent !== null) { // Check if element is visible
                startButton = element;
                usedSelector = selector;
                break;
            }
        }

        if (startButton) {
            setDebug(`Start Tutorial button found with selector: ${usedSelector}, clicking...`);

            // If we found an img, click its parent link
            if (startButton.tagName === 'IMG') {
                const parentLink = startButton.closest('a');
                if (parentLink) {
                    parentLink.click();
                } else {
                    startButton.click();
                }
            } else {
                startButton.click();
            }

            setDebug("Start Tutorial button clicked, waiting for tutorial to load...");
            return true;
        }

        setDebug("Start Tutorial button not found on start page");
        return false;
    }

    function selectRandomAnswer() {
        // Try multiple selector patterns for radio buttons
        const selectorPatterns = [
            ".tut-slides-selectors input[type=radio][name='ans']",
            "input[type=radio][name='ans']",
            ".tut-slides-selectors input[type=radio]",
            "input[type=radio]"
        ];

        let answers = [];
        for (const pattern of selectorPatterns) {
            answers = document.querySelectorAll(pattern);
            if (answers.length > 0) {
                setDebug(`Found ${answers.length} answers using pattern: ${pattern}`);
                break;
            }
        }

        if (answers.length === 0) {
            setDebug("No radio button answers found");
            return false;
        }

        // Check if an answer is already selected
        const alreadySelected = Array.from(answers).find(answer => answer.checked);
        if (alreadySelected) {
            const answerLabel = alreadySelected.nextElementSibling?.textContent || alreadySelected.value;
            setDebug(`Answer already selected: ${answerLabel} (${alreadySelected.value})`);
            return true;
        }

        // Randomly select an answer - FORCE CLICK IT!
        const randomIndex = Math.floor(Math.random() * answers.length);
        const chosen = answers[randomIndex];

        // Get the answer label for better debugging
        const answerLabel = chosen.nextElementSibling?.textContent || chosen.value;

        setDebug(`Attempting to select answer: ${answerLabel} (${chosen.value})`);

        // FORCE the radio button selection using multiple aggressive methods
        try {
            // Method 1: Direct property setting
            chosen.checked = true;

            // Method 2: Focus and click
            chosen.focus();
            chosen.click();

            // Method 3: Simulate mouse events
            chosen.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
            chosen.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
            chosen.dispatchEvent(new MouseEvent('click', { bubbles: true }));

            // Method 4: Form events
            chosen.dispatchEvent(new Event("change", { bubbles: true }));
            chosen.dispatchEvent(new Event("input", { bubbles: true }));

            // Method 5: Try clicking the label too
            const label = chosen.nextElementSibling;
            if (label && label.tagName === 'LABEL') {
                label.click();
            }

            // Verify the selection worked
            setTimeout(() => {
                if (chosen.checked) {
                    setDebug(`SUCCESS: Answer ${answerLabel} is now selected!`);
                } else {
                    setDebug(`FAILED: Answer ${answerLabel} was not selected - trying alternative method`);
                    // Try one more aggressive approach
                    const labelElement = document.querySelector(`label[for="${chosen.id}"]`);
                    if (labelElement) {
                        labelElement.click();
                        setDebug(`Tried clicking label for ${chosen.id}`);
                    }
                }
            }, 100);

            return true;
        } catch (error) {
            setDebug(`Error selecting answer: ${error.message}`);
            return false;
        }
    }

    //////////////////////////
    // Auto Navigation Core //
    //////////////////////////
    function tryAdvance() {
        // FIRST: Check if we're on dashboard and need to start a tutorial
        if (window.location.href.includes('dashboard.html')) {
            const startedTutorial = clickNextStartButton();
            if (startedTutorial) {
                setDebug("Started tutorial from dashboard, waiting for page load...");
                return;
            }
        }

        // SECOND: Check if we're on a start page and need to click Start Tutorial
        if (window.location.pathname.endsWith('/start')) {
            const clickedStartTutorial = clickStartTutorialButton();
            if (clickedStartTutorial) {
                setDebug("Clicked Start Tutorial button, waiting for tutorial to load...");
                return;
            }
        }

        // THIRD: Look for next button (highest priority for tutorial navigation)
        const nextBtnSelectors = [
            "span.tut-slides-next img.complete-tutorial", // Submit button at end
            "span.tut-slides-next img.next-active",
            "button.tut-slides-next img.next-active",
            "span.tut-slides-next",
            "button.tut-slides-next",
            ".tut-slides-next",
            "span[class*='next'] img.next-active",
            "button[class*='next'] img.next-active",
            "img.complete-tutorial", // Direct submit button
            "img.next-active",
            ".next-active",
            ".complete-tutorial"
        ];

        let nextBtn = null;
        let usedSelector = "";

        for (const selector of nextBtnSelectors) {
            const element = document.querySelector(selector);
            if (element && element.offsetParent !== null) { // Check if element is visible
                nextBtn = element;
                usedSelector = selector;
                break;
            }
        }

        if (nextBtn) {
            // Special handling for submit/complete tutorial buttons
            const isSubmitButton = nextBtn.classList?.contains('complete-tutorial') ||
                                 nextBtn.alt === 'Submit' ||
                                 usedSelector.includes('complete-tutorial');

            if (isSubmitButton) {
                setDebug(`Submit/Complete button found with selector: ${usedSelector}, clicking with enhanced method...`);

                // Enhanced clicking for submit buttons
                try {
                    // Method 1: Direct click
                    nextBtn.click();

                    // Method 2: Parent click
                    const parent = nextBtn.closest('span, button');
                    if (parent) {
                        parent.click();
                    }

                    // Method 3: Mouse events
                    nextBtn.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
                    nextBtn.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
                    nextBtn.dispatchEvent(new MouseEvent('click', { bubbles: true }));

                    // Method 4: Focus and click
                    if (parent) {
                        parent.focus();
                        parent.dispatchEvent(new MouseEvent('click', { bubbles: true }));
                    }

                    setDebug("Submit button clicked with multiple methods - tutorial should complete");
                } catch (error) {
                    setDebug(`Error clicking submit button: ${error.message}`);
                }
            } else {
                setDebug(`Next button found with selector: ${usedSelector}, clicking...`);

                // Regular next button handling
                if (nextBtn.tagName === 'IMG') {
                    const parent = nextBtn.closest('span, button');
                    if (parent) {
                        parent.click();
                    } else {
                        nextBtn.click();
                    }
                } else {
                    nextBtn.click();
                }
            }

            setTimeout(() => setDebug("Button clicked, waiting..."), 1000);
            return; // Exit early if we clicked next button
        }

        // FOURTH: Only check for questions if no next button was found
        const question = document.querySelector(".question-title");
        if (question) {
            setDebug("Question detected, no next button available yet");

            // IMMEDIATELY try to select an answer when we find a question
            const answerSelected = selectRandomAnswer();

            if (answerSelected) {
                // Now look for submit button after selecting answer
                const submitBtn = document.querySelector("button.submit-answer");

                if (!submitBtn) {
                    setDebug("Answer selected, but submit button not found, waiting...");
                    return;
                }

                if (submitBtn.disabled) {
                    setDebug("Answer selected, but submit button disabled, waiting...");
                    return;
                }

                setDebug("Answer selected, submitting in 1.5 seconds...");

                // Wait longer to ensure the selection is fully registered
                setTimeout(() => {
                    const currentSubmitBtn = document.querySelector("button.submit-answer");
                    if (currentSubmitBtn && !currentSubmitBtn.disabled) {
                        currentSubmitBtn.click();
                        setDebug("Answer submitted – waiting for next button to appear...");
                    } else {
                        setDebug("Submit button not available after selection, will retry...");
                    }
                }, 1500);
            } else {
                setDebug("Could not select answer, checking for other question types...");
            }
        } else {
            setDebug("No dashboard start buttons, no start tutorial button, no next button, no questions found - waiting...");
        }
    }

    //////////////////////////
    // Main Loop //
    //////////////////////////
    setDebug("GCN Auto-Navigation started.");
    setInterval(tryAdvance, 2000);

})();