Skip to content

Instantly share code, notes, and snippets.

@bagheera02
Created February 14, 2025 15:21
// ==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