Created
February 14, 2025 15:21
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Blueprint Exam Review – Blind Mode | |
// @namespace http://tampermonkey.net/ | |
// @version 1.0 | |
// @description Hide answer feedback on Blueprint exam explanation pages for blind review; improved toggle behavior to reliably hide/reveal answers. | |
// @match https://mcat.blueprintprep.com/exam_explanation/* | |
// @grant none | |
// @run-at document-idle | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
const blindModeClass = 'bp-blind-mode'; | |
let observer = null; | |
let enforcementIntervalId = null; | |
// Utility for debugging | |
function log(message) { | |
console.log("[BP Blind Mode] " + message); | |
} | |
// Inject CSS rules that hide answer feedback elements when blind mode is active. | |
function injectStyles() { | |
const styleContent = ` | |
/* Hide answer feedback elements when blind mode is active */ | |
.${blindModeClass} [class*="radio__option--tooltip"], | |
.${blindModeClass} [class*="radio__option--explanation"], | |
.${blindModeClass} [class*="radio__option_icon"], | |
.${blindModeClass} [class*="radio__option--change-icon"], | |
.${blindModeClass} [class*="radio__option--changed-icon"], | |
.${blindModeClass} [class*="radio__option--show-explanation"], | |
.${blindModeClass} .answer__graph--container, | |
.${blindModeClass} .question__review--information { | |
display: none !important; | |
} | |
`; | |
let styleEl = document.getElementById('bp-blind-style'); | |
if (!styleEl) { | |
styleEl = document.createElement('style'); | |
styleEl.id = 'bp-blind-style'; | |
styleEl.type = 'text/css'; | |
styleEl.textContent = styleContent; | |
document.head.appendChild(styleEl); | |
log("Injected blind mode CSS."); | |
} | |
} | |
// Create and add a floating toggle button. | |
function addToggleButton() { | |
if (document.getElementById('bp-blind-toggle-button')) return; // only add once | |
const toggleButton = document.createElement('button'); | |
toggleButton.id = 'bp-blind-toggle-button'; | |
Object.assign(toggleButton.style, { | |
position: 'fixed', | |
top: '10px', | |
right: '10px', | |
zIndex: '10000', | |
padding: '10px 15px', | |
backgroundColor: '#007bff', | |
color: '#fff', | |
border: 'none', | |
borderRadius: '4px', | |
cursor: 'pointer', | |
fontSize: '14px' | |
}); | |
// Default state: blind mode enabled (answers hidden), so button reads "Reveal Answers" | |
toggleButton.textContent = 'Reveal Answers'; | |
toggleButton.addEventListener('click', function() { | |
if (document.body.classList.contains(blindModeClass)) { | |
// User toggles to reveal answers: remove blind mode and stop auto‑enforcement. | |
document.body.classList.remove(blindModeClass); | |
toggleButton.textContent = 'Blind Answers'; | |
log("Blind mode disabled: answer feedback revealed by user."); | |
stopAutoEnforcement(); | |
} else { | |
// User toggles to hide answers: add blind mode and restart auto‑enforcement. | |
document.body.classList.add(blindModeClass); | |
toggleButton.textContent = 'Reveal Answers'; | |
log("Blind mode enabled: answer feedback hidden by user."); | |
startAutoEnforcement(); | |
} | |
}); | |
document.body.appendChild(toggleButton); | |
log("Toggle button added."); | |
} | |
// Start the MutationObserver to monitor for new review content. | |
function startMutationObserver() { | |
if (observer) return; // already active | |
observer = new MutationObserver((mutations) => { | |
mutations.forEach(mutation => { | |
mutation.addedNodes.forEach(node => { | |
if (node.nodeType === Node.ELEMENT_NODE) { | |
if (node.matches('.question__review--container') || | |
node.querySelector('.question__review--container')) { | |
// If new review content is added while blind mode is on, ensure the class remains. | |
if (!document.body.classList.contains(blindModeClass)) { | |
document.body.classList.add(blindModeClass); | |
log("MutationObserver: Reapplied blind mode due to new review content."); | |
} | |
} | |
} | |
}); | |
}); | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
log("MutationObserver started."); | |
} | |
// Stop the MutationObserver. | |
function stopMutationObserver() { | |
if (observer) { | |
observer.disconnect(); | |
observer = null; | |
log("MutationObserver stopped."); | |
} | |
} | |
// Start the interval check to enforce blind mode on dynamic content. | |
function startIntervalCheck() { | |
if (enforcementIntervalId) return; // already active | |
enforcementIntervalId = setInterval(() => { | |
const reviewContainer = document.querySelector('.question__review--container'); | |
if (reviewContainer && !document.body.classList.contains(blindModeClass)) { | |
document.body.classList.add(blindModeClass); | |
log("Interval check: added blind mode class to body."); | |
} | |
}, 1000); | |
log("Interval check started."); | |
} | |
// Stop the interval check. | |
function stopIntervalCheck() { | |
if (enforcementIntervalId) { | |
clearInterval(enforcementIntervalId); | |
enforcementIntervalId = null; | |
log("Interval check stopped."); | |
} | |
} | |
// Start both auto‑enforcement mechanisms. | |
function startAutoEnforcement() { | |
startMutationObserver(); | |
startIntervalCheck(); | |
} | |
// Stop both auto‑enforcement mechanisms. | |
function stopAutoEnforcement() { | |
stopMutationObserver(); | |
stopIntervalCheck(); | |
} | |
// Initialization function. | |
function init() { | |
injectStyles(); | |
// By default, enable blind mode. | |
document.body.classList.add(blindModeClass); | |
addToggleButton(); | |
startAutoEnforcement(); | |
log("Blueprint Exam Review Blind Mode script initialized."); | |
} | |
if (document.readyState === "complete" || document.readyState === "interactive") { | |
init(); | |
} else { | |
document.addEventListener("DOMContentLoaded", init); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment