Testout Retry

Remove the Lab Score Report window on testout labs to fix what you missed and quickly resubmit.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Testout Retry
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  Remove the Lab Score Report window on testout labs to fix what you missed and quickly resubmit.
// @author       Ultimate
// @match        https://cdn.testout.com/*
// ==/UserScript==

let scoreReportOpen = false;
let lastRetryTime = -1;
let retry = 0;
const prefix = '[Retry] ';
log('INJECTED INTO IFRAME');

//Set interval for checking if lab report is open
setInterval(() => {
    let pre = scoreReportOpen;
    const doneBtn = getDoneBtn();
    scoreReportOpen = doneBtn !== null;
    if (pre != scoreReportOpen) onLabScoreOpened();
}, 100);

function onLabScoreOpened() {
    if (Date.now() - lastRetryTime < 500) return;
    log('SCORE WINDOW OPENED');
    const doneBtn = getDoneBtn();

    if (doneBtn == null || doneBtn == undefined) return;

    //Add our own button
    const retryBtn = document.createElement('button');
    retryBtn.innerText = 'Retry Lab';
    retryBtn.style = 'position: absolute; z-index: 99999; overflow: visible; color: #dd2575; display: inherit; left: 1135px; top: 793px; border-width: 0px; width: 31px; height: 14px; text-align: left; font-family: Arial; font-weight: bold; font-size: 9pt; text-overflow: clip; overflow-wrap: normal; white-space: nowrap;';

    retryBtn.addEventListener('click', () => {
        log('REMOVING LAB SCORE WINDOW..');
        lastRetryTime = Date.now();

        const removeElements = [
            'ScoreReportWindow.Grid',
            'bWindow',
            'DockPanel.Border',
            'DockPanel.Border.Panel.tbTitle',
            'Background',
            'Background.Grid',
            'BackgroundGradient',
            'bPrint.Grid.contentPresenter.Image',
            'DockPanel.Border1',
            'DockPanel.Border1.StackPanel.Border',
            'svResults',
            'pnConnecting.TextBlock',
            'btDone.Grid.Border',
            'btDone.Grid.Border.NormalElement',
            'btDone.Grid.Border.NormalElement.Border',
            'btDone.Grid.contentPresenter.TextBlock',
            'UIRoot.ScoreReportWindow.Grid.bWindow.DockPanel.Border1.StackPanel.Panel.btDone.Grid.Border.NormalElement.Border',
            'UIRoot.ScoreReportWindow.Grid.bWindow.DockPanel.Border1.StackPanel.Panel.btDone.Grid.MouseOverElement',
            '_ifrmreport_',
            'bWindow.DockPanel'
        ];

        retryBtn.remove();

        let removed = 0;

        //Method 1
        removeElements.forEach(id => {
            let el = document.querySelector('#'+id.replace(/\./g, '\\.')); //.s replaced with \\. so it doesnt think its a class
            if (el !== null) {
                el.remove();
                removed++;
            }
        });

        //Method 2 - Loop through all elements because testout changes the names each score for some reason
        const all = document.querySelectorAll('.clsFrameworkElement');
        for (let i = 1; i < all.length; i++) {
            if (all[i].style.zIndex >= 99999 || all[i].id.includes('ScoreReport') || all[i].id.includes('bWindow.DockPanel')) {
                all[i].remove();
                removed++;
            }
        }

        log(`Successfully removed ${removed} elements and destroyed score report window.`); //Done!
        retry++;
    });

    if (doneBtn !== null) doneBtn.parentNode.appendChild(retryBtn);
}

//For some reason on rescore the id is different
function getDoneBtn() {
   const all = document.querySelectorAll('.clsFrameworkElement');

    for (let i = 1; i < all.length; i++) {
        if (all[i].id.includes('Done') && all[i].innerText === 'Done' && all[i].style.display === 'inherit') {
            return all[i];
        }
    }

    return null;
}

function log(msg) {
    console.log(prefix+msg);
}