laat alle antwoorden zien

voeg "laat alle antwoorden zien" toe

// ==UserScript==
// @name         laat alle antwoorden zien
// @version      0.6
// @description  voeg "laat alle antwoorden zien" toe
// @match        https://apps.noordhoff.nl/*
// @run-at       document-start
// @author       Jouke van Dam
// @namespace https://greasyfork.org/users/1511158
// ==/UserScript==

(function() {
	'use strict';

	// inject real script into page context (avoids userscript sandbox issues)
	const injectedCode = function() {
		'use strict';
		const TAG = '[NoordhoffInjector]';

		console.log(TAG, 'running in page context — initializing interceptor');

		// helper: try to parse JSON and force isTeacher if relevant; return modified string or null if nothing changed
		function tryModifyResponseText(text) {
			if (!text) return null;
			try {
				const obj = JSON.parse(text);
				if (obj && obj.data && obj.data.me) {
					console.log(TAG, 'found data.me — original isTeacher =', obj.data.me.isTeacher);
					obj.data.me.isTeacher = true;
					console.log(TAG, 'forced data.me.isTeacher = true');
					return JSON.stringify(obj);
				}
			} catch (e) {
				// not JSON — ignore
			}
			return null;
		}

		// ------- patch fetch -------
		try {
			const _fetch = window.fetch;
			window.fetch = async function(input, init) {
				try {
					const url = (typeof input === 'string') ? new URL(input, location.origin).href : (input && input.url) || '';
					if (url && url.includes('/se/api/')) {
						console.log(TAG, 'fetch -> intercepted request to', url, 'init:', init);
						const resp = await _fetch.apply(this, arguments);
						const clone = resp.clone();
						const text = await clone.text();
						const modified = tryModifyResponseText(text);
						if (modified !== null) {
							const newHeaders = new Headers(resp.headers);
							if (!newHeaders.has('content-type')) newHeaders.set('content-type', 'application/json');
							const newResp = new Response(modified, {
								status: resp.status,
								statusText: resp.statusText,
								headers: newHeaders
							});
							console.log(TAG, 'fetch -> returning modified Response for', url);
							return newResp;
						} else {
							console.log(TAG, 'fetch -> response had no data.me; passing through for', url);
							return resp;
						}
					}
				} catch (err) {
					console.error(TAG, 'fetch wrapper error', err);
				}
				return _fetch.apply(this, arguments);
			};
			console.log(TAG, 'fetch patched');
		} catch (e) {
			console.error(TAG, 'failed to patch fetch', e);
		}

		// ------- patch XMLHttpRequest -------
		try {
			const origOpen = XMLHttpRequest.prototype.open;
			XMLHttpRequest.prototype.open = function(method, url) {
				try {
					this._ni_url = url ? new URL(url, location.origin).href : '';
				} catch (e) {
					this._ni_url = url || '';
				}
				return origOpen.apply(this, arguments);
			};

			const origSend = XMLHttpRequest.prototype.send;
			XMLHttpRequest.prototype.send = function(body) {
				try {
					const url = this._ni_url || '';
					if (url && url.includes('/se/api/')) {
						console.log(TAG, 'XHR -> send to', url, 'body preview:', (typeof body === 'string') ? body.slice(0, 300) : (body ? '[object]' : '[empty]'));
						const onLoad = () => {
							try {
								const txt = this.responseText;
								const modified = tryModifyResponseText(txt);
								if (modified !== null) {
									// try best-effort to override responseText/response
									try {
										Object.defineProperty(this, 'responseText', { value: modified, configurable: true });
										Object.defineProperty(this, 'response', { value: modified, configurable: true });
										console.log(TAG, 'XHR -> modified responseText/response for', url);
									} catch (e) {
										console.warn(TAG, 'XHR -> could not redefine responseText/response on instance', e);
									}
								} else {
									console.log(TAG, 'XHR -> response had no data.me for', url);
								}
							} catch (e) {
								console.error(TAG, 'XHR onload handler error', e);
							}
						};
						this.addEventListener('load', onLoad);
					}
				} catch (e) {
					console.error(TAG, 'XHR send wrapper error', e);
				}
				return origSend.apply(this, arguments);
			};
			console.log(TAG, 'XMLHttpRequest patched');
		} catch (e) {
			console.error(TAG, 'failed to patch XHR', e);
		}

		console.log(TAG, 'interceptor active — forcing data.me.isTeacher = true for /se/api/ responses when present');
	};

	// create script tag and inject into page
	const s = document.createElement('script');
	s.setAttribute('data-noordhoff-inject', '1');
	s.textContent = '(' + injectedCode.toString() + ')();';

	// If documentElement exists, append immediately; otherwise wait DOMContentLoaded
	if (document.documentElement) {
		document.documentElement.appendChild(s);
		console.log('[NoordhoffInjector] injected script tag into page');
	} else {
		window.addEventListener('DOMContentLoaded', () => {
			document.documentElement.appendChild(s);
			console.log('[NoordhoffInjector] injected script tag after DOMContentLoaded');
		});
	}
})();