// ==UserScript==
// @name D2L Auto-Advance v7.3
// @namespace d2l-autoadvance-v7
// @version 7.3
// @description Auto-advances D2L Brightspace. F7=Toggle UI, F8=Start/Stop, F9=Next
// @match https://*.modernstates.org/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// ── Only run in the TOP frame, never in iframes ────────────────────
if (window !== window.top) return;
// ── Kill any previous instance + nuke all old UIs ─────────────────
document.querySelectorAll('#d2l-aa').forEach(e => e.remove());
if (window.__d2lAA) { try { window.__d2lAA.kill(); } catch (_) {} delete window.__d2lAA; }
const MIN_MS = 3000, MAX_MS = 4000;
const rand = () => MIN_MS + Math.floor(Math.random() * (MAX_MS - MIN_MS));
function getLinks() {
const results = [];
function walk(node) {
if (!node) return;
try {
node.querySelectorAll('d2l-activity-link[href]').forEach(el => results.push(el));
node.querySelectorAll('*').forEach(el => { if (el.shadowRoot) walk(el.shadowRoot); });
} catch (_) {}
}
walk(document);
return results;
}
function getCurrentIndex(links) {
const i = links.findIndex(l => l.hasAttribute('is-current-activity'));
return i >= 0 ? i : 0;
}
function clickLink(link) {
if (!link) return;
link.click();
try {
const inner = link.shadowRoot?.querySelector('a, button, [role="link"]');
if (inner) inner.click();
} catch (_) {}
link.scrollIntoView({ behavior: 'smooth', block: 'center' });
console.log('[D2L v7.3] →', link.getAttribute('href')?.split('/').pop());
}
let idx = -1, running = false, mainT = null, tickT = null, secs = 0, uiVisible = true;
// ── Build UI ───────────────────────────────────────────────────────
const ui = document.createElement('div');
ui.id = 'd2l-aa';
ui.style.cssText = `
position:fixed;bottom:18px;right:18px;z-index:2147483647;
background:#0d1117;color:#cdd6e0;
font:13px/1.5 "Segoe UI",Arial,sans-serif;
padding:12px 15px;border-radius:11px;
box-shadow:0 4px 24px rgba(0,0,0,.85);
min-width:235px;border:1px solid #30363d;
transition:opacity 0.3s,transform 0.3s;
`;
ui.innerHTML = `
⚡ D2L Auto-Advance
Scanning...
0 / 0
F7=Hide · F8=Start/Stop · F9=Next
`;
document.body.appendChild(ui);
const el = id => document.getElementById(id);
const setS = (t, c='#8b949e') => { const e=el('d2l-aa-s'); if(e){e.textContent=t;e.style.color=c;} };
const setP = (i, n) => { const e=el('d2l-aa-p'); if(e) e.textContent=`${i} / ${n}`; };
const setC = t => { const e=el('d2l-aa-c'); if(e) e.textContent=t||' '; };
const setB = (t, bg) => { const e=el('d2l-aa-b0'); if(e){e.textContent=t;e.style.background=bg;} };
function clearTimers() {
clearTimeout(mainT); clearInterval(tickT); mainT = tickT = null;
}
function advance() {
const links = getLinks();
if (!links.length) { setS('⚠ No links found', '#e3b341'); return false; }
if (idx < 0) idx = getCurrentIndex(links);
else idx++;
if (idx >= links.length) {
setS('✅ All done!', '#3fb950'); setP(links.length, links.length);
setC('Complete!'); running = false; clearTimers(); setB('▶ F8', '#238636');
return false;
}
clickLink(links[idx]);
setS('▶ Running', '#3fb950');
setP(idx + 1, links.length);
setC(`Activity ${links[idx].getAttribute('href')?.split('/').pop().split('?')[0] || ''}`);
return true;
}
function schedule() {
if (!running) return;
clearTimers();
const ms = rand();
secs = Math.ceil(ms / 1000);
setC(`Next in ${secs}s`);
tickT = setInterval(() => {
secs--;
setC(secs > 0 ? `Next in ${secs}s` : 'Advancing…');
if (secs <= 0) clearInterval(tickT);
}, 1000);
mainT = setTimeout(() => { if (running && advance()) schedule(); }, ms);
}
function toggleAuto() {
if (running) {
running = false; clearTimers();
setS('⏸ Paused', '#e3b341'); setB('▶ F8', '#238636');
} else {
const links = getLinks();
if (!links.length) { setS('⚠ No links — reload page', '#e3b341'); return; }
if (idx < 0) idx = getCurrentIndex(links) - 1;
running = true; setB('⏸ F8', '#e3b341');
if (advance()) schedule();
}
}
function manualNext() {
clearTimers();
if (advance() && running) schedule();
}
function reset() {
running = false; idx = -1; clearTimers();
const links = getLinks();
setS('↺ Reset — press F8', '#8b949e');
setP(0, links.length); setC(' '); setB('▶ F8', '#238636');
}
function toggleUI() {
uiVisible = !uiVisible;
ui.style.opacity = uiVisible ? '1' : '0';
ui.style.pointerEvents = uiVisible ? 'auto' : 'none';
ui.style.transform = uiVisible ? 'translateY(0)' : 'translateY(20px)';
}
el('d2l-aa-b0').onclick = toggleAuto;
el('d2l-aa-b1').onclick = manualNext;
el('d2l-aa-b2').onclick = reset;
function onKey(e) {
if (e.key === 'F7') { e.preventDefault(); toggleUI(); }
if (e.key === 'F8') { e.preventDefault(); toggleAuto(); }
if (e.key === 'F9') { e.preventDefault(); manualNext(); }
}
document.addEventListener('keydown', onKey, true);
function init(attempts = 0) {
const links = getLinks();
if (links.length > 0) {
idx = getCurrentIndex(links) - 1;
setS(`✅ ${links.length} links — press F8`, '#3fb950');
setP(0, links.length);
console.log(`[D2L v7.3] Ready. ${links.length} links found.`);
} else if (attempts < 10) {
setTimeout(() => init(attempts + 1), 1000);
} else {
setS('⚠ No links found', '#e3b341');
}
}
setTimeout(() => init(), 1500);
window.__d2lAA = {
initialized: true,
kill() {
running = false; clearTimers();
document.getElementById('d2l-aa')?.remove();
document.removeEventListener('keydown', onKey, true);
delete window.__d2lAA;
}
};
})();