Advertisement

Responsive Advertisement

N17

// --- Question Timer Function --- function startQuestionTimer() { if (currentQuestionIndex !== null && questions[currentQuestionIndex]) { const question = questions[currentQuestionIndex]; const questionKey = `${currentPart}-${question.originalNumber}`; if (!questionStartTimes[questionKey]) { questionStartTimes[questionKey] = Date.now(); } } } // --- Initialize Watermark --- function initializeWatermark() { const watermarkContainers = document.querySelectorAll('.watermark-pt-container'); watermarkContainers.forEach(container => { const containerWidth = container.offsetWidth; const containerHeight = container.offsetHeight; const watermarkText = '8016820***'; const spacingX = 150; const spacingY = 100; for (let y = -50; y < containerHeight + 50; y += spacingY) { for (let x = -50; x < containerWidth + 50; x += spacingX) { const watermark = document.createElement('div'); watermark.className = 'watermark-pt-text'; watermark.textContent = watermarkText; watermark.style.left = `${x}px`; watermark.style.top = `${y}px`; container.appendChild(watermark); } } }); } // --- Render Question Grid --- function renderQuestionGrid(part) { questionGridEl.innerHTML = ''; solutionQuestionGridEl.innerHTML = ''; const questionsInPart = allQuestionsByPart[part] || []; questionsInPart.forEach((question, index) => { const gridItem = document.createElement('div'); gridItem.className = `question-grid-item ${question.status} ${index === currentQuestionIndex && part === currentPart ? 'current' : ''}`; gridItem.textContent = question.originalNumber; gridItem.dataset.index = index; gridItem.dataset.part = part; gridItem.innerHTML += '
'; gridItem.addEventListener('click', () => { saveCurrentQuestionTime(); currentPart = part; currentQuestionIndex = index; questions = allQuestionsByPart[part]; updateQuestionDisplay(); updateQuestionGrid(); startQuestionTimer(); }); questionGridEl.appendChild(gridItem); const solutionGridItem = document.createElement('div'); const { bgColor, textColor } = getQuestionPaletteColorClasses(question); solutionGridItem.className = `question-grid-item ${index === currentQuestionIndex && part === currentPart ? 'current' : ''} ${bgColor} ${textColor}`; solutionGridItem.textContent = question.originalNumber; solutionGridItem.dataset.index = index; solutionGridItem.dataset.part = part; solutionGridItem.innerHTML += '
'; solutionGridItem.addEventListener('click', () => { currentPart = part; currentQuestionIndex = index; questions = allQuestionsByPart[part]; updateSolutionDisplay(); updateSolutionQuestionGrid(); }); solutionQuestionGridEl.appendChild(solutionGridItem); }); } // --- Update Question Display --- function updateQuestionDisplay() { if (!questions[currentQuestionIndex]) return; const question = questions[currentQuestionIndex]; questionNumberSpan.textContent = question.originalNumber; questionTextCell.innerHTML = question.question; optionsTableBody.innerHTML = ''; question.options.forEach((option, index) => { const optionLetter = String.fromCharCode(97 + index); const row = document.createElement('tr'); row.innerHTML = ` ${option} `; optionsTableBody.appendChild(row); }); questionTextCell.style.fontSize = `${currentQuestionTextFontSize}px`; optionsTableBody.querySelectorAll('.text-cell').forEach(cell => { cell.style.fontSize = `${currentOptionTextFontSize}px`; }); markReviewBtn.classList.toggle('marked-active', question.status.includes('marked')); question.status = question.status === 'not-visited' ? 'not-answered' : question.status; renderKatex(); updateAnalysisSummary(); } // --- Update Solution Display --- function updateSolutionDisplay() { if (!questions[currentQuestionIndex]) return; const question = questions[currentQuestionIndex]; solutionQuestionNumberSpan.textContent = question.originalNumber; solutionQuestionTextCell.innerHTML = question.question; solutionOptionsTableBody.innerHTML = ''; question.options.forEach((option, index) => { const optionLetter = String.fromCharCode(97 + index); const isCorrect = option.includes(`(${question.answer})`); const isUserAnswer = question.userAnswer === option; const optionClass = isCorrect ? 'solution-option-correct' : (isUserAnswer && !isCorrect ? 'solution-option-incorrect' : 'solution-option-normal'); const row = document.createElement('tr'); row.innerHTML = ` ${option} `; solutionOptionsTableBody.appendChild(row); }); solutionDummyContent.innerHTML = question.solution; solutionQuestionTextCell.style.fontSize = `${currentQuestionTextFontSize}px`; solutionOptionsTableBody.querySelectorAll('.text-cell').forEach(cell => { cell.style.fontSize = `${currentOptionTextFontSize}px`; }); renderKatex(); updateSolutionAnalysisSummary(); } // --- Update Analysis Summary --- function updateAnalysisSummary() { const questionsInPart = allQuestionsByPart[currentPart] || []; const answeredCount = questionsInPart.filter(q => q.userAnswer !== null).length; const notAnsweredCount = questionsInPart.length - answeredCount; answeredCountEl.textContent = answeredCount; notAnsweredCountEl.textContent = notAnsweredCount; totalAnsweredEl.textContent = Object.values(allQuestionsByPart).flat().filter(q => q.userAnswer !== null).length; currentPartAnalysisTitle.textContent = partNames[currentPart]; partTitleEl.textContent = partNames[currentPart]; } // --- Update Solution Analysis Summary --- function updateSolutionAnalysisSummary() { const questionsInPart = allQuestionsByPart[currentPart] || []; const answeredCount = questionsInPart.filter(q => q.userAnswer !== null).length; const notAnsweredCount = questionsInPart.length - answeredCount; solutionAnsweredCountEl.textContent = answeredCount; solutionNotAnsweredCountEl.textContent = notAnsweredCount; solutionTotalAnsweredEl.textContent = Object.values(allQuestionsByPart).flat().filter(q => q.userAnswer !== null).length; solutionCurrentPartAnalysisTitle.textContent = partNames[currentPart]; solutionPartTitleEl.textContent = partNames[currentPart]; } // --- Render KaTeX --- function renderKatex() { [questionTextCell, optionsTableBody, solutionQuestionTextCell, solutionOptionsTableBody, solutionDummyContent].forEach(element => { if (element) { renderMathInElement(element, { delimiters: [ { left: "$$", right: "$$", display: true }, { left: "$", right: "$", display: false }, { left: "\\(", right: "\\)", display: false }, { left: "\\[", right: "\\]", display: true } ], throwOnError: false }); } }); } // --- Start Total Timer --- function startTotalTimer() { totalTestStartTime = Date.now(); const totalDurationMs = TOTAL_TEST_DURATION_MINUTES * 60 * 1000; totalTimerInterval = setInterval(() => { const elapsed = Date.now() - totalTestStartTime; const remaining = Math.max(totalDurationMs - elapsed, 0); timeLeftEl.textContent = formatHoursMinutesSeconds(remaining); lastMinutesDisplay.textContent = Math.ceil(remaining / 60000); if (remaining <= 0) { clearInterval(totalTimerInterval); showAlert('Time is up! Submitting test.', 'Test Ended', (confirm) => { if (confirm) submitTest(); }); } }, 1000); } // --- Populate Review Submit Modal --- function populateReviewSubmitModal() { reviewSummaryTableBody.innerHTML = ''; partOrder.forEach(part => { const questionsInPart = allQuestionsByPart[part] || []; const answered = questionsInPart.filter(q => q.userAnswer !== null).length; const notAnswered = questionsInPart.length - answered; const markedAnswered = questionsInPart.filter(q => q.status === 'answered-marked').length; const markedForReview = questionsInPart.filter(q => q.status.includes('marked')).length; const visited = questionsInPart.filter(q => q.status !== 'not-visited').length; const notVisited = questionsInPart.length - visited; const row = document.createElement('tr'); row.innerHTML = ` ${partNames[part]} ${questionsInPart.length} ${answered} ${notAnswered} ${markedAnswered} ${markedForReview} ${visited} ${notVisited} `; reviewSummaryTableBody.appendChild(row); }); reviewSubmitModal.style.display = 'flex'; } // --- Submit Test --- function submitTest() { saveCurrentQuestionTime(); clearInterval(totalTimerInterval); totalTestEndTime = Date.now(); testCompletionDateTime = new Date(); solutionCompletionTimeEl.textContent = `${formatDate(testCompletionDateTime)} ${formatTime(testCompletionDateTime)}`; mocktestPage.classList.add('hidden'); solutionPage.classList.remove('hidden'); inSolutionMode = true; currentPart = partOrder[0]; questions = allQuestionsByPart[currentPart]; currentQuestionIndex = 0; updateSolutionDisplay(); updateSolutionQuestionGrid(); updateSolutionAnalysisSummary(); initializeWatermark(); } // --- Generate PDF --- async function generatePDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'portrait', unit: 'px', format: 'a4' }); pdfContentWrapper.innerHTML = ''; Object.keys(allQuestionsByPart).forEach(part => { const questionsInPart = allQuestionsByPart[part] || []; if (questionsInPart.length > 0) { const partHeader = document.createElement('h2'); partHeader.textContent = `Part ${part}: ${partNames[part]}`; pdfContentWrapper.appendChild(partHeader); questionsInPart.forEach((question, index) => { const questionDiv = document.createElement('div'); questionDiv.className = 'question-feedback-item'; questionDiv.innerHTML = `

Question ${question.originalNumber}: ${partNames[part]}

${question.question}

${question.options.map((option, i) => { const isCorrect = option.includes(`(${question.answer})`); const isUserAnswer = question.userAnswer === option; const optionClass = isCorrect ? 'correct' : (isUserAnswer && !isCorrect ? 'incorrect' : ''); return `
${option}
`; }).join('')}
Solution: ${question.solution}
`; pdfContentWrapper.appendChild(questionDiv); }); } }); const charts = document.querySelectorAll('.chart-container canvas'); for (let i = 0; i < charts.length; i++) { const canvas = charts[i]; const chartImg = canvas.toDataURL('image/png'); const imgDiv = document.createElement('div'); imgDiv.className = 'chart-container pdf-chart'; imgDiv.innerHTML = ``; pdfContentWrapper.appendChild(imgDiv); } const elements = pdfContentWrapper.querySelectorAll('.question-feedback-item, h2, .chart-container'); let yPosition = 20; for (let element of elements) { const tempDiv = document.createElement('div'); tempDiv.style.width = '754px'; tempDiv.style.padding = '10px'; tempDiv.innerHTML = element.outerHTML; document.body.appendChild(tempDiv); const canvas = await html2canvas(tempDiv, { scale: 2 }); const imgData = canvas.toDataURL('image/png'); const imgProps = doc.getImageProperties(imgData); const pdfWidth = doc.internal.pageSize.getWidth() - 40; const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; if (yPosition + pdfHeight > doc.internal.pageSize.getHeight() - 20) { doc.addPage(); yPosition = 20; } doc.addImage(imgData, 'PNG', 20, yPosition, pdfWidth, pdfHeight); yPosition += pdfHeight + 20; document.body.removeChild(tempDiv); } doc.save(`${currentTopic || 'Mock_Test'}_Feedback.pdf`); pdfContentWrapper.innerHTML = ''; } // --- Event Listeners --- document.addEventListener('DOMContentLoaded', async () => { await fetchQuestions(); initializeWatermark(); questions = allQuestionsByPart[currentPart] || []; if (questions.length > 0) { renderQuestionGrid(currentPart); updateQuestionDisplay(); } else { questionGridEl.innerHTML = '

No questions available.

'; } updateAnalysisSummary(); }); startMocktestBtn.addEventListener('click', () => { allQuestionsByPart['A'] = parseQuestions(questionInputPartA.value); allQuestionsByPart['B'] = parseQuestions(questionInputPartB.value); allQuestionsByPart['C'] = parseQuestions(questionInputPartC.value); allQuestionsByPart['D'] = parseQuestions(questionInputPartD.value); currentTopic = topicInput.value.trim() || 'General'; const totalQuestions = Object.values(allQuestionsByPart).flat().length; if (totalQuestions === 0) { showAlert('Please enter at least one valid question to start the test.'); return; } inputPage.classList.add('hidden'); mocktestPage.classList.remove('hidden'); currentPart = partOrder[0]; questions = allQuestionsByPart[currentPart]; currentQuestionIndex = 0; renderQuestionGrid(currentPart); updateQuestionDisplay(); updateAnalysisSummary(); startTotalTimer(); startQuestionTimer(); initializeWatermark(); }); optionsTableBody.addEventListener('change', (e) => { if (e.target.type === 'radio') { questions[currentQuestionIndex].userAnswer = e.target.value; questions[currentQuestionIndex].status = questions[currentQuestionIndex].status.includes('marked') ? 'answered-marked' : 'answered'; updateQuestionGrid(); updateAnalysisSummary(); } }); partTabs.forEach(tab => { tab.addEventListener('click', () => { saveCurrentQuestionTime(); partTabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); currentPart = tab.dataset.part; questions = allQuestionsByPart[currentPart] || []; currentQuestionIndex = 0; renderQuestionGrid(currentPart); updateQuestionDisplay(); updateAnalysisSummary(); startQuestionTimer(); }); }); solutionPartTabs.forEach(tab => { tab.addEventListener('click', () => { currentPart = tab.dataset.part; questions = allQuestionsByPart[currentPart] || []; currentQuestionIndex = 0; solutionPartTabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); renderQuestionGrid(currentPart); updateSolutionDisplay(); updateSolutionAnalysisSummary(); }); }); prevBtn.addEventListener('click', () => { saveCurrentQuestionTime(); if (currentQuestionIndex > 0) { currentQuestionIndex--; } else { const currentPartIndex = partOrder.indexOf(currentPart); if (currentPartIndex > 0) { currentPart = partOrder[currentPartIndex - 1]; questions = allQuestionsByPart[currentPart]; currentQuestionIndex = questions.length - 1; partTabs.forEach(tab => tab.classList.toggle('active', tab.dataset.part === currentPart)); } } updateQuestionDisplay(); updateQuestionGrid(); startQuestionTimer(); }); saveNextBtn.addEventListener('click', () => { saveCurrentQuestionTime(); if (currentQuestionIndex < questions.length - 1) { currentQuestionIndex++; } else { const currentPartIndex = partOrder.indexOf(currentPart); if (currentPartIndex < partOrder.length - 1) { currentPart = partOrder[currentPartIndex + 1]; questions = allQuestionsByPart[currentPart]; currentQuestionIndex = 0; partTabs.forEach(tab => tab.classList.toggle('active', tab.dataset.part === currentPart)); } } updateQuestionDisplay(); updateQuestionGrid(); startQuestionTimer(); }); markReviewBtn.addEventListener('click', () => { const question = questions[currentQuestionIndex]; if (question.status.includes('marked')) { question.status = question.userAnswer ? 'answered' : 'not-answered'; } else { question.status = question.userAnswer ? 'answered-marked' : 'marked'; } updateQuestionGrid(); updateQuestionDisplay(); }); submitTestBtn.addEventListener('click', () => { populateReviewSubmitModal(); }); confirmSubmitTestBtn.addEventListener('click', () => { reviewSubmitModal.style.display = 'none'; submitTest(); }); zoomInBtn.addEventListener('click', () => { currentQuestionTextFontSize += 2; currentOptionTextFontSize += 2; updateQuestionDisplay(); }); zoomOutBtn.addEventListener('click', () => { if (currentQuestionTextFontSize > 12) { currentQuestionTextFontSize -= 2; currentOptionTextFontSize -= 2; updateQuestionDisplay(); } }); solutionZoomInBtn.addEventListener('click', () => { currentQuestionTextFontSize += 2; currentOptionTextFontSize += 2; updateSolutionDisplay(); }); solutionZoomOutBtn.addEventListener('click', () => { if (currentQuestionTextFontSize > 12) { currentQuestionTextFontSize -= 2; currentOptionTextFontSize -= 2; updateSolutionDisplay(); } }); fullscreenBtn.addEventListener('click', () => { if (!document.fullscreenElement) { mocktestPage.requestFullscreen().then(() => { fullscreenBtn.textContent = 'Exit Fullscreen'; }).catch(err => console.error('Fullscreen error:', err)); } else { document.exitFullscreen().then(() => { fullscreenBtn.textContent = 'Show Fullscreen'; }); } }); solutionFullscreenBtn.addEventListener('click', () => { if (!document.fullscreenElement) { solutionPage.requestFullscreen().then(() => { solutionFullscreenBtn.textContent = 'Exit Fullscreen'; }).catch(err => console.error('Fullscreen error:', err)); } else { document.exitFullscreen().then(() => { solutionFullscreenBtn.textContent = 'Show Fullscreen'; }); } }); hideLeftPanelBtn.addEventListener('click', () => { const isHidden = leftPanel.style.width === '0px'; leftPanel.style.width = isHidden ? '360px' : '0px'; rightPanel.style.width = isHidden ? 'calc(100% - 360px)' : '100%'; hideLeftPanelBtn.querySelector('img').src = isHidden ? 'https://www.testranking.in/next_images/test/pt-left.png' : 'https://www.testranking.in/next_images/test/pt-right.png'; }); solutionHideLeftPanelBtn.addEventListener('click', () => { const isHidden = solutionLeftPanel.style.width === '0px'; solutionLeftPanel.style.width = isHidden ? '360px' : '0px'; solutionRightPanel.style.width = isHidden ? 'calc(100% - 360px)' : '100%'; solutionHideLeftPanelBtn.querySelector('img').src = isHidden ? 'https://www.testranking.in/next_images/test/pt-left.png' : 'https://www.testranking.in/next_images/test/pt-right.png'; }); solutionPrevBtn.addEventListener('click', () => { if (currentQuestionIndex > 0) { currentQuestionIndex--; } else { const currentPartIndex = partOrder.indexOf(currentPart); if (currentPartIndex > 0) { currentPart = partOrder[currentPartIndex - 1]; questions = allQuestionsByPart[currentPart]; currentQuestionIndex = questions.length - 1; solutionPartTabs.forEach(tab => tab.classList.toggle('active', tab.dataset.part === currentPart)); } } updateSolutionDisplay(); updateSolutionQuestionGrid(); }); solutionNextBtn.addEventListener('click', () => { if (currentQuestionIndex < questions.length - 1) { currentQuestionIndex++; } else { const currentPartIndex = partOrder.indexOf(currentPart); if (currentPartIndex < partOrder.length - 1) { currentPart = partOrder[currentPartIndex + 1]; questions = allQuestionsByPart[currentPart]; currentQuestionIndex = 0; solutionPartTabs.forEach(tab => tab.classList.toggle('active', tab.dataset.part === currentPart)); } } updateSolutionDisplay(); updateSolutionQuestionGrid(); }); backToResultBtn.addEventListener('click', () => { solutionPage.classList.add('hidden'); resultPage.classList.remove('hidden'); // Result page logic can be added here if needed }); symbolsTab.addEventListener('click', () => { symbolsModal.style.display = 'block'; isSymbolsModalOpen = true; }); instructionsTab.addEventListener('click', () => { showAlert('Instructions: Select one option per question. Use the navigation buttons to move between questions. Save and mark questions as needed.'); }); closeModalBtn.addEventListener('click', () => { symbolsModal.style.display = 'none'; isSymbolsModalOpen = false; }); // --- Initialize --- document.addEventListener('DOMContentLoaded', () => { initializeWatermark(); });

Post a Comment

0 Comments