// ==UserScript== // @name VLA Toolkit — Copy/Paste & Session Keep-Alive // @namespace https://github.com/COMPLEXWASTAKEN/vla-tampermonkey // @version 1.4.0 // @description Unlocks copy/paste on Virtual Learning Academy lesson questions and keeps your session alive automatically. // @author COMPLEXWASTAKEN // @license MIT // @homepageURL https://github.com/COMPLEXWASTAKEN/vla-tampermonkey#readme // @supportURL https://github.com/COMPLEXWASTAKEN/vla-tampermonkey/issues // @updateURL https://raw.githubusercontent.com/COMPLEXWASTAKEN/vla-tampermonkey/main/vla-enable-copy-paste.user.js // @downloadURL https://raw.githubusercontent.com/COMPLEXWASTAKEN/vla-tampermonkey/main/vla-enable-copy-paste.user.js // @match https://virtuallearningacademy.net/Student/* // @match https://www.virtuallearningacademy.net/Student/* // @run-at document-start // @grant none // @inject-into page // ==/UserScript== (function () { 'use strict'; const isRealPage = (doc) => { const href = doc?.location?.href || ''; return href && href !== 'about:blank' && !href.startsWith('about:'); }; const injectPageScript = (doc, source, markerName) => { if (!doc?.documentElement) { return false; } const href = doc.location?.href || 'top'; const markerKey = 'data-vla-' + markerName; if (doc.documentElement.getAttribute(markerKey) === href) { return false; } doc.documentElement.setAttribute(markerKey, href); const script = doc.createElement('script'); script.textContent = source; (doc.head || doc.documentElement).appendChild(script); script.remove(); return true; }; const unlockSource = String.raw`(() => { const href = location.href; if (!href || href === 'about:blank' || href.startsWith('about:')) { return; } const initKey = 'data-vla-unlock-init'; if (document.documentElement.getAttribute(initKey) === href) { return; } document.documentElement.setAttribute(initKey, href); const noopAllow = () => true; const clipboardEvents = new Set(['copy', 'cut', 'paste', 'selectstart', 'contextmenu']); const lockBlocker = (name) => { try { Object.defineProperty(window, name, { configurable: true, writable: false, value: noopAllow }); } catch (e) { window[name] = noopAllow; } }; ['blockCopy', 'blockPaste', 'blockCtrlKeys'].forEach(lockBlocker); const origPreventDefault = Event.prototype.preventDefault; Event.prototype.preventDefault = function () { if (clipboardEvents.has(this.type)) { return; } return origPreventDefault.call(this); }; const style = document.createElement('style'); style.id = 'vla-unlock-copy'; style.textContent = [ 'body, body * {', '-webkit-user-select: text !important;', '-moz-user-select: text !important;', '-ms-user-select: text !important;', 'user-select: text !important;', '}' ].join('\n'); const injectStyle = () => { if (!document.getElementById('vla-unlock-copy')) { (document.head || document.documentElement).appendChild(style); } }; const unlockElement = (el) => { el.classList.remove('no-copy'); el.removeAttribute('oncopy'); el.removeAttribute('oncut'); el.removeAttribute('onpaste'); el.removeAttribute('oncontextmenu'); el.removeAttribute('onselectstart'); el.removeAttribute('ondragstart'); el.style.setProperty('-webkit-user-select', 'text', 'important'); el.style.setProperty('user-select', 'text', 'important'); }; const unlockPage = () => { injectStyle(); ['blockCopy', 'blockPaste', 'blockCtrlKeys'].forEach(lockBlocker); document.querySelectorAll('.no-copy, [oncopy], [oncut], [onpaste], [oncontextmenu], [onselectstart]').forEach(unlockElement); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', unlockPage); } else { unlockPage(); } new MutationObserver(unlockPage).observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'oncopy', 'oncut', 'onpaste', 'oncontextmenu', 'onselectstart'] }); })();`; const keepAliveSource = String.raw`(() => { if (window.__vlaKeepAliveActive) { return; } window.__vlaKeepAliveActive = true; const isWarningVisible = () => { const overlay = document.getElementById('timeOutWarningOverlay'); return overlay && window.getComputedStyle(overlay).display !== 'none'; }; const clickStaySignedIn = () => { if (!isWarningVisible()) { return false; } const keep = document.getElementById('keep'); if (!keep) { return false; } keep.click(); return true; }; const refreshSession = () => { if (typeof resetTimer === 'function') { resetTimer(); } if (typeof KeepSessionAlive === 'function') { KeepSessionAlive(); } clickStaySignedIn(); }; const start = () => { if (!document.getElementById('keep') && !document.getElementById('timeOutWarningOverlay')) { return; } refreshSession(); setInterval(refreshSession, 20 * 60 * 1000); setInterval(clickStaySignedIn, 3000); const overlay = document.getElementById('timeOutWarningOverlay'); if (overlay) { new MutationObserver(clickStaySignedIn).observe(overlay, { attributes: true, attributeFilter: ['style', 'class'] }); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } })();`; const injectUnlock = (doc) => { if (!doc || !doc.documentElement || !isRealPage(doc)) { return false; } const href = doc.location?.href || ''; if (doc.documentElement.getAttribute('data-vla-unlock') === href) { return false; } doc.documentElement.setAttribute('data-vla-unlock', href); doc.documentElement.removeAttribute('data-vla-unlock-init'); return injectPageScript(doc, unlockSource, 'unlock-script'); }; const hookIframe = (iframe) => { if (!iframe || iframe.dataset.vlaUnlockHooked === '1') { return; } iframe.dataset.vlaUnlockHooked = '1'; iframe.addEventListener('load', () => { try { const doc = iframe.contentDocument; if (doc) { injectUnlock(doc); } } catch (e) {} }); }; let scanTimer = null; const hookQuestionIframes = () => { hookIframe(document.getElementById('DisplayQuestions2')); document.querySelectorAll('iframe').forEach((iframe) => { const iframeSrc = iframe.getAttribute('src') || ''; if (/LessonQuestions\.aspx/i.test(iframeSrc)) { hookIframe(iframe); } }); }; const scheduleIframeScan = () => { clearTimeout(scanTimer); scanTimer = setTimeout(hookQuestionIframes, 100); }; const initKeepAlive = () => { if (window !== window.top) { return; } injectPageScript(document, keepAliveSource, 'keepalive-script'); }; const path = location.pathname || ''; if (/LessonQuestions\.aspx/i.test(path)) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => injectUnlock(document)); } else { injectUnlock(document); } } if (/LessonRead\.aspx/i.test(path)) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', hookQuestionIframes); } else { hookQuestionIframes(); } new MutationObserver(scheduleIframeScan).observe(document.documentElement, { childList: true, subtree: true }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initKeepAlive); } else { initKeepAlive(); } })();