let questionid=""; window.onload = () => resetState(); document.addEventListener('DOMContentLoaded', () => { resetState(); jsonDataFetched = false; }); function toggleModal(){document.getElementById("modal").classList.toggle("hidden")} function toggleMS(){document.getElementById("markscheme").classList.toggle("hidden")} function toggleR(){document.getElementById("report").classList.toggle("hidden")} function toggleHelp(){document.getElementById("helpmenu").classList.toggle("hidden")} function toggleDownAllQs(){document.getElementById("addalltoPDFbtn").classList.remove('hidden');document.getElementById("generatePDFbtn").classList.remove('hidden')} function toggleDarkMode() { var body = document.body; var head = document.head; var toggleButton = document.getElementById("darkmodebtn"); if (localStorage.getItem("darkMode") === "disabled") { body.classList.add("dark-mode"); head.classList.add("dark-mode"); localStorage.setItem("darkMode", "enabled"); toggleButton.innerText = "Light Mode"; } else { body.classList.remove("dark-mode"); head.classList.remove("dark-mode"); localStorage.setItem("darkMode", "disabled"); toggleButton.innerText = "Dark Mode"; } } document.addEventListener("DOMContentLoaded", () => { const darkModeStatus = localStorage.getItem("darkMode"); const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches; if (darkModeStatus === "enabled") { document.body.classList.add("dark-mode"); document.head.classList.add("dark-mode"); document.getElementById("darkmodebtn").innerText = "Light Mode"; } else if (darkModeStatus === "disabled") { document.body.classList.remove("dark-mode"); document.head.classList.remove("dark-mode"); document.getElementById("darkmodebtn").innerText = "Dark Mode"; } else if (prefersDarkScheme) { document.body.classList.add("dark-mode"); document.head.classList.add("dark-mode"); document.getElementById("darkmodebtn").innerText = "Light Mode"; localStorage.setItem("darkMode", "enabled"); } else { document.body.classList.remove("dark-mode"); document.head.classList.remove("dark-mode"); document.getElementById("darkmodebtn").innerText = "Dark Mode"; localStorage.setItem("darkMode", "disabled"); } }); function startRandomTimerLoop() { var randomTime = Math.floor(11 * Math.random()) + 20; setTimeout(() => { alert("Provided by pirateIB\nhttps://pirateib.xyz"); startRandomTimerLoop(); }, 60 * randomTime * 1000); } window.onload = function() { setTimeout(() => { startRandomTimerLoop(); }, 300000); }; /*function generatePDF() { const selectedQuestionIds = JSON.parse(sessionStorage.getItem("selectedQuestionIds")) || []; if (0 === selectedQuestionIds.length) return alert("Select some questions first!"); const printWindow = window.open("", "_blank"); printWindow.document.write('\n \n \n QuestionBank Test\n \n \n \n \n '); let concatenatedHTML = ""; let markschemesHTML = ''; selectedQuestionIds.forEach((questionId => { const questionDiv = document.getElementById(questionId), h3 = questionDiv.querySelector("h3"), squareContainer = questionDiv.querySelector(".square-container"); concatenatedHTML += h3.outerHTML + squareContainer.outerHTML const msDiv = document.querySelector(`[id*="markscheme-${questionId}"]`); const cloneMsDiv = msDiv.cloneNode(true); cloneMsDiv.classList.remove('hidden'); markschemesHTML += h3.outerHTML + cloneMsDiv.outerHTML; })), printWindow.document.write(`

Questions


${concatenatedHTML}

Markschemes


${markschemesHTML}`), printWindow.document.write("\n \n \n "), printWindow.document.close(); setTimeout(() => { printWindow.print(), printWindow.onafterprint = () => printWindow.close(); }, 1000);}*/ function generatePDF() { const selectedQuestionIds = JSON.parse(sessionStorage.getItem("selectedQuestionIds")) || []; if (0 === selectedQuestionIds.length) return alert("Select some questions first!"); // Prompt the user for including markschemes let includeMarkschemes = null; while (includeMarkschemes !== "yes" && includeMarkschemes !== "no") { includeMarkschemes = prompt("Do you want to include markschemes? (yes/no)").toLowerCase(); if (includeMarkschemes !== "yes" && includeMarkschemes !== "no") { alert("Please answer 'yes' or 'no'."); } } const printWindow = window.open("", "_blank"); printWindow.document.write('\n \n \n QuestionBank Test\n \n \n \n \n '); let concatenatedHTML = ""; let markschemesHTML = ''; selectedQuestionIds.forEach((questionId) => { const questionDiv = document.getElementById(questionId), h3 = questionDiv.querySelector("h3"), squareContainer = questionDiv.querySelector(".square-container"); concatenatedHTML += h3.outerHTML + squareContainer.outerHTML; if (includeMarkschemes === "yes") { const msDiv = document.querySelector(`[id*="markscheme-${questionId}"]`); const cloneMsDiv = msDiv.cloneNode(true); cloneMsDiv.classList.remove('hidden'); markschemesHTML += h3.outerHTML + cloneMsDiv.outerHTML; } }); printWindow.document.write(`

Questions


${concatenatedHTML}`); if (includeMarkschemes === "yes") { printWindow.document.write(`

Markschemes


${markschemesHTML}`); } printWindow.document.write("\n \n \n "); printWindow.document.close(); setTimeout(() => { printWindow.print(); printWindow.onafterprint = () => printWindow.close(); }, 1000); } function addalltoPDF() { const buttons = document.querySelectorAll('.btn-secondary'); buttons.forEach(button => { if (button.textContent.trim() === "Add to PDF" && !button.parentElement.parentElement.classList.contains('hidden')) { button.click(); } }); } let jsonDataFetched = false; let jsonData = null; let currentFileName = null; let topics = []; const domCache = { rightCol: document.getElementById("right-col"), msbox: document.getElementById("markscheme-box"), reportbox: document.getElementById("report-box"), msbox2: document.getElementById("markscheme-box2"), repbox2: document.getElementById("report-box2"), leftCol: document.getElementById('left-col') }; document.addEventListener('keydown', (event) => { if (event.key === 'Escape') { const modal = document.getElementById('modal'); const helpmenu = document.getElementById('helpmenu'); if (modal && !modal.classList.contains('hidden')) { toggleModal(); } else if (helpmenu && !helpmenu.classList.contains('hidden')) { toggleHelp(); } } }); const fileNameMap = { 'bioqb': 'Biology QB.json', 'bmqb': 'Business Management QB.json', 'chemqb': 'Chemistry QB.json', 'compsciqb': 'Computer Science QB.json', 'destechqb': 'Design Technology QB.json', 'digsocqb': 'Digital Society QB.json', 'econqb': 'Economics QB.json', 'essqb': 'ESS QB.json', 'geoqb': 'Geography QB.json', 'histqb': 'History QB.json', 'mathaaqb': 'Math AA QB.json', 'mathaiqb': 'Math AI QB.json', 'phyqb': 'Physics QB.json', 'psychqb': 'Psychology QB.json', 'sehsqb': 'SEHS QB.json' }; function createSVGElement(questionid) { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); const attributes = { "width": "2rem", "height": "2rem", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }; Object.entries(attributes).forEach(([key, value]) => { svg.setAttribute(key, value); }); svg.classList.add("cursor-pointer", "text-primary", "hidden"); svg.innerHTML = ` `; return svg; } function showLoading() { document.getElementById('loadingBanner').style.display = 'block'; } function hideLoading() { document.getElementById('loadingBanner').style.display = 'none'; } function openDatabase() { return new Promise((resolve, reject) => { const request = indexedDB.open('myDatabase', 1); request.onupgradeneeded = (event) => { const db = event.target.result; if (!db.objectStoreNames.contains('myStore')) { db.createObjectStore('myStore'); } }; request.onsuccess = (event) => { resolve(event.target.result); }; request.onerror = (event) => { reject('Error opening database:', event.target.error); }; }); } async function loadJSON(filename) { showLoading(); const db = await openDatabase(); const cachedData = await new Promise((resolve, reject) => { const transaction = db.transaction('myStore', 'readonly'); const store = transaction.objectStore('myStore'); const request = store.get(filename); request.onsuccess = (event) => { resolve(event.target.result); }; request.onerror = (event) => { reject('Error fetching data from IndexedDB:', event.target.error); }; }); if (cachedData) { hideLoading(); processData(cachedData, filename); return; } try { const response = await fetch(`../assets/jsonqb/${filename}`); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); await new Promise((resolve, reject) => { const transaction = db.transaction('myStore', 'readwrite'); const store = transaction.objectStore('myStore'); const request = store.put(data, filename); request.onsuccess = () => { resolve(); }; request.onerror = (event) => { reject('Error storing data in IndexedDB:', event.target.error); }; }); sessionStorage.setItem('selectedQuestionIds', '[]'); setTimeout(() => { processData(data, filename); hideLoading(); sessionStorage.setItem('selectedQuestionIds', '[]'); }, 0); } catch (error) { console.error('Error fetching JSON:', error); hideLoading(); sessionStorage.setItem('selectedQuestionIds', '[]'); } } function processData(data, filename) { jsonDataFetched = true; currentFileName = filename; topics = [...new Set(data.flatMap(item => item.topics))].sort(); renderTopics(); const fragment = document.createDocumentFragment(); data.forEach(item => { const { Question: question, question_id: questionid, Markscheme: markscheme, 'Examiners report': report, topics, subtopics } = item; const bigQuestionBox = document.createElement("div"); bigQuestionBox.id = questionid; const allClasses = [...topics.map(t => t.trim()), ...subtopics.map(s => s.trim()), "hidden"]; bigQuestionBox.classList.add(...allClasses); const btnContainer = document.createElement("div"); btnContainer.classList.add("btn-container"); function toggleMScont(questionid) { const markschemeContainer = document.getElementById(`markscheme-${questionid} ${currentFileName}`); toggleMSSvg.classList.toggle('hidden'); markschemeContainer.classList.toggle('hidden'); activeQuestionId = markschemeContainer.classList.contains('hidden') ? null : questionid; } function toggleRepcont(questionid) { const reportContainer = document.getElementById(`report-${questionid} ${currentFileName}`); toggleRepSvg.classList.toggle('hidden'); reportContainer.classList.toggle('hidden'); activeQuestionId = reportContainer.classList.contains('hidden') ? null : questionid; } const buttons = [ { text: "Markscheme", handler: () => { toggleMS(); toggleMScont(questionid); } }, { text: "Examiners report", handler: () => { toggleR(); toggleRepcont(questionid); } }, { text: "Add to PDF", handler: createPDFButtonHandler(questionid) } ].map(createButton); buttons.forEach(button => btnContainer.appendChild(button)); const content = `

${questionid}

Topics: ${topics.join(', ')}

Subtopics: ${subtopics.join(', ')}

${question}
`; bigQuestionBox.innerHTML = content; bigQuestionBox.querySelector('h3').after(btnContainer); if (markscheme) { createContainer('markscheme', questionid, filename, markscheme, domCache.msbox); } if (report) { createContainer('report', questionid, filename, report, domCache.reportbox); } /********** Removed ID appending method since it was slowing down interaction with the X svg *********/ const toggleMSSvg = createSVGElement(questionid); //toggleMSSvg.id = `toggleMSSvg-${questionid}`; const toggleRepSvg = createSVGElement(questionid); //toggleRepSvg.id = `toggleRepSvg-${questionid}`; domCache.msbox2.appendChild(toggleMSSvg); domCache.repbox2.appendChild(toggleRepSvg); /*toggleMSSvg.addEventListener('click', () => { toggleMScont(questionid); toggleMS(); });*/ /********** Identifying by active question instead **********/ let activeQuestionId = null; const handleToggle = () => { if (activeQuestionId) { const markschemeContainer = document.getElementById(`markscheme-${activeQuestionId} ${currentFileName}`); const reportContainer = document.getElementById(`report-${activeQuestionId} ${currentFileName}`); if (markschemeContainer && !markschemeContainer.classList.contains('hidden')) { toggleMSSvg.classList.toggle('hidden'); toggleMS(); markschemeContainer.classList.toggle('hidden'); activeQuestionId = null; } else if (reportContainer && !reportContainer.classList.contains('hidden')) { toggleRepSvg.classList.toggle('hidden'); toggleR(); reportContainer.classList.toggle('hidden'); activeQuestionId = null; } } } toggleMSSvg.addEventListener('click', handleToggle); toggleRepSvg.addEventListener('click', handleToggle); document.addEventListener('keydown', (event) => { if (event.key === 'Escape') { handleToggle(); } }); /*toggleRepSvg.addEventListener('click', () => { toggleRepcont(questionid); toggleR(); });*/ fragment.appendChild(bigQuestionBox); }); domCache.rightCol.appendChild(fragment); updateSquareContainers(); toggleDownAllQs(); } /******** Old function for fetching JSON, deprecated in favor of IndexedDB ********/ /*function loadJSON(filename) { fetch(`https://pub-59370068cd854c158959e7ca4578e5bd.r2.dev/${filename}`) // ../assets/jsonqb/ .then(response => response.json()) .then(data => { jsonDataFetched = true; currentFileName = filename; topics = [...new Set(data.flatMap(item => item.topics))].sort(); renderTopics(); const fragment = document.createDocumentFragment(); data.forEach(item => {}); domCache.rightCol.appendChild(fragment); updateSquareContainers(); }) .catch(error => console.error('Error fetching JSON:', error)); }*/ function createButton({ text, handler, className = 'btn-secondary' }) { const button = document.createElement("button"); button.classList.add(className); button.textContent = text; button.addEventListener('click', handler); return button; } function createPDFButtonHandler(questionid) { return function () { let selectedQuestionIds = JSON.parse(sessionStorage.getItem('selectedQuestionIds')) || []; const index = selectedQuestionIds.indexOf(questionid); if (index !== -1) { selectedQuestionIds.splice(index, 1); this.style.backgroundColor = 'rgb(66 165 245)'; this.textContent = 'Add to PDF'; } else { selectedQuestionIds.push(questionid); this.style.backgroundColor = '#e03b3b'; this.textContent = 'Added!'; } sessionStorage.setItem('selectedQuestionIds', JSON.stringify(selectedQuestionIds)); }; } function createContainer(type, questionid, filename, content, parent) { const container = document.createElement("div"); container.classList.add("square-container", "hidden"); container.id = `${type}-${questionid} ${filename}`; container.innerHTML = content; parent.appendChild(container); } function renderTopics() { const fragment = document.createDocumentFragment(); topics.forEach(topic => { const label = document.createElement('label'); label.classList.add('topic-label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.name = 'topic'; checkbox.value = topic; checkbox.addEventListener('change', () => { document.querySelectorAll(`div[class*="${topic}"]`) .forEach(div => div.classList.toggle('hidden')); }); label.append(checkbox, topic); fragment.appendChild(label); }); domCache.leftCol.appendChild(fragment); } function updateSquareContainers() { document.querySelectorAll('.square-container').forEach(container => { const firstChild = container.children[0]; if (firstChild?.classList.contains('question')) { firstChild.classList.replace('question', 'specification'); } }); } document.addEventListener('DOMContentLoaded', () => { document.addEventListener('click', event => { const filename = fileNameMap[event.target.id]; if (!filename) return; if (jsonDataFetched && filename !== currentFileName) { resetState(); loadJSON(filename); //} else if (jsonDataFetched && filename === currentFileName) { //resetState(); //jsonDataFetched = false; } else if (!jsonDataFetched) { loadJSON(filename); } }); }); function resetState() { domCache.rightCol.innerHTML = ''; document.querySelectorAll('.topic-label').forEach(label => label.remove()); sessionStorage.setItem('selectedQuestionIds', '[]'); }