Untitled

 avatar
unknown
plain_text
9 months ago
23 kB
18
Indexable
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Kuis: Komunikasi Sel — Final (40 soal, per-halaman, shuffle, timers)</title>
<style>
  :root{--bg:#f7fafc;--card:#fff;--muted:#6b7280;--accent:#0ea5a4}
  body{font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial;background:var(--bg);margin:0;padding:18px;color:#0f172a}
  .wrap{max-width:980px;margin:18px auto;background:var(--card);padding:22px;border-radius:12px;box-shadow:0 8px 28px rgba(2,6,23,0.06)}
  h1{margin:0 0 6px;font-size:22px}
  .meta{color:var(--muted);font-size:14px;margin-bottom:10px}
  .timers{display:flex;gap:12px;align-items:center;margin-bottom:12px}
  .timerBox{background:#eef7f6;padding:8px 12px;border-radius:10px;border:1px solid #e6f6f4;color:#044e4b;font-weight:700}
  .progressWrap{height:10px;background:#e6eef8;border-radius:999px;overflow:hidden;margin:8px 0 18px}
  .bar{height:100%;background:var(--accent);width:0%}
  .card{padding:18px;border-radius:10px;border:1px solid #eef6f6;background:#fbfdff}
  .question{font-weight:700;margin-bottom:12px;font-size:16px}
  .choices label{display:block;padding:10px;border-radius:8px;margin:8px 0;cursor:pointer;border:1px solid transparent}
  .choices input{margin-right:10px}
  .btns{display:flex;gap:10px;margin-top:14px;align-items:center}
  button{background:var(--accent);color:white;border:none;padding:10px 14px;border-radius:10px;cursor:pointer;font-weight:700}
  button.ghost{background:#e6eef8;color:#0f172a}
  .feedback{margin-top:12px;padding:12px;border-radius:8px;display:none}
  .feedback.correct{background:#ecfdf5;border:1px solid #bbf7d0;color:#064e3b}
  .feedback.wrong{background:#fff1f2;border:1px solid #fecaca;color:#991b1b}
  .feedback.skip{background:#fff7ed;border:1px solid #ffd9b8;color:#7a4d00}
  .explain{margin-top:8px;color:#374151}
  .footer{margin-top:18px;color:var(--muted);font-size:13px}
  .resultBox{text-align:center;padding:18px;border-radius:10px;background:#f8fafc;border:1px solid #e6eef8;margin-top:14px}
  details{margin:8px 0;border-left:3px solid #e6eef8;padding:8px 12px;border-radius:6px;background:#ffffff}
  .small{font-size:13px;color:var(--muted)}
  .muted{color:var(--muted);font-size:13px}
</style>
</head>
<body>
<div class="wrap">
  <h1>KUIS: Komunikasi Sel — Final</h1>
  <div class="meta">40 soal • Bahasa Indonesia • Feedback langsung • Soal diacak tiap mulai</div>

  <div class="timers">
    <div class="timerBox">Sisa Waktu Total: <span id="totalTimer">20:00</span></div>
    <div class="timerBox">Waktu Soal: <span id="qTimer">0:30</span></div>
    <div style="margin-left:auto" class="muted" id="qCounter">Soal 1 / 40</div>
  </div>

  <div class="progressWrap" aria-hidden><div class="bar" id="progressBar"></div></div>

  <div id="quizArea" class="card">
    <!-- question injected here -->
  </div>

  <div class="btns" id="navBtns" style="display:none">
    <button id="submitBtn">Jawab</button>
    <button id="nextBtn" class="ghost" style="display:none">Next →</button>
    <button id="skipBtn" class="ghost" title="Lewati soal ini tanpa skor">Lewati</button>
    <button id="restartBtn" class="ghost" style="display:none">Ulangi Kuis</button>
    <div style="margin-left:auto" class="small" id="statusInfo"></div>
  </div>

  <div id="finalArea"></div>

  <div class="footer">Sumber materi: <em>KUL 4 KOMUNIKASI SEL (VI).pdf</em>. :contentReference[oaicite:1]{index=1}</div>
</div>

<script>
/* ===== QUESTIONS (40) - ringkasan dari PDF KUL 4 KOMUNIKASI SEL (VI) ===== */
const baseQuestions = [
  {q:"Apa yang dimaksud dengan \"first messenger\"?", choices:["Molekul intraseluler yang meneruskan sinyal","Molekul sinyal asal luar sel yang mengikat reseptor","Molekul yang memecah second messenger","Enzim yang mengubah ATP menjadi cAMP"], a:1, explain:"First messenger = molekul sinyal dari luar (hormon, neurotransmiter) yang mengikat reseptor."},
  {q:"Manakah contoh pensinyalan jarak jauh?", choices:["Parakrin","Sinaps","Endokrin (hormonal)","Pengenalan antarsel"], a:2, explain:"Endokrin melepaskan hormon ke sirkulasi darah untuk menjangkau sel jauh."},
  {q:"Reseptor yang ada di sitoplasma atau nukleus biasanya diaktifkan oleh:", choices:["Molekul besar larut air","Molekul hidrofobik/kecil yang menembus membran","Ion Ca²⁺ saja","ATP"], a:1, explain:"Molekul kecil/hidrofobik (mis. steroid) menembus membran dan mengikat reseptor intraseluler."},
  {q:"Yang termasuk reseptor membran utama adalah semua berikut kecuali:", choices:["Ligand-gated ion channel","Receptor tyrosine kinase (RTK)","G protein–coupled receptor (GPCR)","DNA polymerase"], a:3, explain:"DNA polymerase bukan reseptor membran."},
  {q:"Aktivasi reseptor tirosin kinase biasanya melibatkan:", choices:["Dimerisasi & autofosforilasi tirosin","Pembukaan saluran ion","Pembentukan NO langsung di sel target","Pertukaran GDP-GTP pada subunit alfa"], a:0, explain:"RTK berpasangan (dimer) lalu saling mengfosforilasi residu tirosin."},
  {q:"Pada reseptor GPCR, aktivasi protein G dicirikan oleh:", choices:["Pengikatan ATP","Pertukaran GDP menjadi GTP pada subunit alfa","Fosforilasi residu serin","Pelepasan NO"], a:1, explain:"Subunit alfa menukar GDP→GTP sehingga protein G aktif."},
  {q:"cAMP terbentuk dari:", choices:["ATP melalui adenylyl cyclase","GTP melalui guanylyl cyclase","AMP yang ditambah fosfat","Fosfodiesterase"], a:0, explain:"Adenylyl cyclase mengubah ATP menjadi cAMP."},
  {q:"Enzim yang memecah cAMP menjadi AMP adalah:", choices:["Adenylyl cyclase","Phosphodiesterase","Protein kinase A","NO synthase"], a:1, explain:"Phosphodiesterase (PDE) memecah cAMP menjadi AMP."},
  {q:"Salah satu efek epinefrin pada sel hati adalah:", choices:["Menghambat pemecahan glikogen","Mengaktifkan pemecahan glikogen melalui cAMP","Meningkatkan pembentukan NO","Menurunkan Ca²⁺ sitosol secara langsung"], a:1, explain:"Epinefrin meningkatkan cAMP → aktivasi jalur pemecahan glikogen."},
  {q:"Nitric oxide (NO) berfungsi sebagai:", choices:["Ligand untuk GPCR","Gas yang berdifusi & mengaktifkan guanylyl cyclase","Second messenger yang dipecah PDE","Ion yang disimpan di ER"], a:1, explain:"NO berdifusi ke sel target dan mengaktifkan guanylyl cyclase → cGMP."},
  {q:"Aktivasi guanylyl cyclase oleh NO meningkatkan:", choices:["cGMP","cAMP","ATP","DAG"], a:0, explain:"Guanylyl cyclase mengubah GTP menjadi cGMP."},
  {q:"Mengapa konsentrasi Ca²⁺ di sitosol dijaga sangat rendah?", choices:["Agar Ca²⁺ tidak mengikat calmodulin","Agar perubahan kecil Ca²⁺ cepat memicu respons","Karena Ca²⁺ selalu beracun","Karena Ca²⁺ diproduksi setelah fosforilasi"], a:1, explain:"Gradient rendah memungkinkan respons cepat saat Ca²⁺ dilepas."},
  {q:"Molekul IP₃ bekerja dengan:", choices:["Mengaktifkan reseptor ion di membran plasma","Mengikat IP₃-gated channel di ER melepaskan Ca²⁺","Mengubah ATP menjadi cAMP","Menghambat kinase"], a:1, explain:"IP3 membuka kanal Ca²⁺ di ER → pelepasan Ca²⁺."},
  {q:"DAG berfungsi sebagai:", choices:["Second messenger di membran & mengaktifkan PKC","Pemicu pelepasan Ca²⁺ dari ER","Enzim pemecah PIP2","Inhibitor adenylyl cyclase"], a:0, explain:"DAG di membran mengaktifkan PKC bersama Ca²⁺."},
  {q:"Apa fungsi protein calmodulin?", choices:["Mengikat Ca²⁺ & mengaktifkan protein target","Memecah cAMP","Menyimpan Ca²⁺ di ER","Membentuk NO"], a:0, explain:"Calmodulin mengikat Ca²⁺ lalu mengaktifkan kinases/fosfatases."},
  {q:"Kaskade fosforilasi umumnya melibatkan:", choices:["Rangkaian protein kinase yang saling mengaktifkan","Sekumpulan ion kompleks","Enzim yang memecah DNA","Perubahan pH"], a:0, explain:"Satu kinase mengaktifkan kinase lain → kaskade."},
  {q:"Enzim yang menghapus gugus fosfat disebut:", choices:["Protein kinase","Protein phosphatase","Adenylyl cyclase","Phospholipase C"], a:1, explain:"Protein phosphatase melepaskan fosfat (Pi) → defosforilasi."},
  {q:"Keuntungan jalur multistep adalah:", choices:["Menghilangkan reseptor","Amplifikasi sinyal","Mengurangi spesifisitas","Menurunkan produk aktif"], a:1, explain:"Setiap langkah dapat memperbanyak produk aktif → amplifikasi."},
  {q:"Scaffolding proteins membantu transduksi sinyal dengan:", choices:["Memecah ATP","Mengumpulkan komponen jalur agar interaksi lebih efisien","Menghambat kinase","Menimbun Ca²⁺"], a:1, explain:"Scaffold mengumpulkan protein agar transfer sinyal cepat/akurat."},
  {q:"Dua sel merespon sinyal yang sama berbeda karena:", choices:["Koleksi protein intraseluler berbeda","Perbedaan pH darah","Letak sel saja","Jumlah mitokondria"], a:0, explain:"Perbedaan koleksi protein intraseluler menentukan respons."},
  {q:"Ion channel yang terbuka karena perubahan tegangan disebut:", choices:["Ligand-gated channel","Voltage-gated channel","Aquaporin","Gap junction"], a:1, explain:"Voltage-gated channel merespons perubahan tegangan membran."},
  {q:"Ligand-gated ion channel terbuka bila:", choices:["Tegangan berubah","Ligan berikatan pada kanal","cAMP menurun","Fosfat dilepas"], a:1, explain:"Ligand (neurotransmiter) mengikat → kanal terbuka."},
  {q:"Contoh penyakit yang berhubungan dengan disfungsi protein G adalah:", choices:["Kolera & Pertusis","Diabetes tipe 1","Hemofilia","Anemia sel sabit"], a:0, explain:"Toksin kolera/pertusis memodifikasi protein G → gangguan sinyal."},
  {q:"Pada jalur GPCR yang meningkatkan cAMP, kinase utama adalah:", choices:["PKA","PKC","Tyrosine kinase","Guanylyl cyclase"], a:0, explain:"cAMP mengaktifkan PKA (serin/treonin kinase)."},
  {q:"Fosforilasi protein umumnya menggunakan gugus fosfat dari:", choices:["GTP","ATP","cAMP","Pi bebas"], a:1, explain:"Protein kinase memindahkan gugus fosfat dari ATP."},
  {q:"Fosfat inorganik (Pi) muncul selama defosforilasi karena:", choices:["ATP jadi AMP","Phosphatase melepaskan fosfat dari protein","cAMP jadi GTP","Ca²⁺ dilepas"], a:1, explain:"Defosforilasi melepaskan Pi dari protein."},
  {q:"Peran phospholipase C (PLC) adalah:", choices:["Memotong PIP2 menjadi DAG & IP3","Mengubah ATP → cAMP","Mengaktifkan guanylyl cyclase","Menyintesis NO"], a:0, explain:"PLC memotong PIP2 → DAG + IP3."},
  {q:"IP3 menyebabkan pelepasan Ca²⁺ dari:", choices:["Mitokondria","Retikulum endoplasma (ER)","Sitosol","Nukleus"], a:1, explain:"IP3 membuka kanal Ca²⁺ di ER."},
  {q:"Aktivasi NO synthase pada endotel dapat dipicu oleh:", choices:["Asetilkolin","cAMP langsung","Phosphodiesterase","Scaffold protein"], a:0, explain:"Asetilkolin merangsang NO synthase di sel endotel."},
  {q:"Reaksi pembentukan NO biologis:", choices:["Glukosa → NO","Arginin → NO (oleh NO synthase)","ATP → NO","Ca²⁺ → NO"], a:1, explain:"NO dibuat dari arginin oleh NO synthase."},
  {q:"Efek utama kenaikan cGMP di otot polos adalah:", choices:["Kontraksi","Relaksasi","Sintesis glikogen","Aktivasi PKA"], a:1, explain:"cGMP menyebabkan relaksasi otot polos (vasodilatasi)."},
  {q:"PDE yang dihambat sildenafil memecah:", choices:["cAMP","cGMP","ATP","IP3"], a:1, explain:"Sildenafil menghambat PDE yang memecah cGMP."},
  {q:"Apa yang terjadi pada protein relay setelah menempel pada fosfotirosin RTK?", choices:["Didegradasi","Perubahan konformasi/aktivasi","Keluar sel","Mengikat DNA langsung"], a:1, explain:"Protein relay aktif setelah berikatan dengan fosfotirosin."},
  {q:"Defosforilasi protein memungkinkan:", choices:["Kinase terus aktif","Mematikan sinyal dan mengembalikan protein","Membentuk cAMP","Meningkatkan Ca²⁺"], a:1, explain:"Defosforilasi mematikan sinyal dan memulihkan protein."},
  {q:"Mengapa kaskade fosforilasi menyebabkan amplifikasi?", choices:["Karena setiap kinase hanya aktif satu target","Karena tiap langkah jumlah produk aktif meningkat","Karena phosphatase meningkatkan sinyal","Karena sinyal langsung ke nukleus"], a:1, explain:"Satu kinase dapat mengaktifkan banyak target → amplifikasi."},
  {q:"IP3 & DAG berasal dari pemotongan fosfolipid apa?", choices:["PIP2","ATP","cAMP","LDL"], a:0, explain:"PIP2 dipotong oleh PLC menjadi IP3 & DAG."},
  {q:"Contoh ligan yang bekerja pada endotel untuk menghasilkan NO:", choices:["Asetilkolin","Glukagon","Insulin","cAMP"], a:0, explain:"Asetilkolin merangsang NO synthase di endotel."},
  {q:"Fungsi utama pompa Ca²⁺ di membran & ER:", choices:["Akumulasi Ca²⁺ di sitosol","Menjaga Ca²⁺ sitosolik rendah & menyimpan untuk pelepasan","Mengubah Ca²⁺ jadi Mg²⁺","Menyintesis IP3"], a:1, explain:"Pompa menjaga Ca²⁺ rendah di sitosol dan menyimpan di ER."},
  {q:"Mengapa sel punya mekanisme mematikan jalur sinyal (phosphatase/PDE)?", choices:["Agar sinyal terus menerus","Untuk mengatur durasi & intensitas respons","Untuk meningkatkan semua sinyal","Karena enzim itu tidak penting"], a:1, explain:"Mematikan jalur mengatur durasi/intensitas agar sel siap menerima sinyal baru."},
  {q:"Perbedaan utama parakrin vs endokrin:", choices:["Parakrin lewat darah","Parakrin lokal; endokrin lewat darah","Keduanya sama","Parakrin selalu neuron"], a:1, explain:"Parakrin bekerja lokal; endokrin lewat sirkulasi darah."}
];

/* ===== SETTINGS ===== */
const TOTAL_TIME_SEC = 20 * 60; // 20 minutes
const PER_QUESTION_SEC = 30;     // 30 seconds per question

/* ===== state ===== */
let questionOrder = []; // indices after shuffle
let currentIdx = 0;     // index into questionOrder
let score = 0;
let skipped = 0;
let answered = 0;
let totalSecondsLeft = TOTAL_TIME_SEC;
let perQSecondsLeft = PER_QUESTION_SEC;
let totalTimerInterval = null;
let perQTimerInterval = null;
let quizStarted = false;

/* ===== DOM refs ===== */
const quizArea = document.getElementById('quizArea');
const totalTimerEl = document.getElementById('totalTimer');
const qTimerEl = document.getElementById('qTimer');
const qCounter = document.getElementById('qCounter');
const progressBar = document.getElementById('progressBar');
const navBtns = document.getElementById('navBtns');
const submitBtn = document.getElementById('submitBtn');
const nextBtn = document.getElementById('nextBtn');
const skipBtn = document.getElementById('skipBtn');
const restartBtn = document.getElementById('restartBtn');
const finalArea = document.getElementById('finalArea');
const statusInfo = document.getElementById('statusInfo');

/* ===== helpers ===== */
function pad(n){ return n<10? '0'+n : ''+n; }
function formatTime(s){ return pad(Math.floor(s/60))+':'+pad(s%60); }
function shuffleArray(a){
  const arr = a.slice();
  for(let i=arr.length-1;i>0;i--){
    const j = Math.floor(Math.random()*(i+1));
    [arr[i],arr[j]]=[arr[j],arr[i]];
  }
  return arr;
}

/* Initialize quiz: shuffle and prepare */
function startQuiz(){
  // shuffle questions order
  questionOrder = shuffleArray(baseQuestions.map((_,i)=>i));
  currentIdx = 0;
  score = 0; skipped = 0; answered = 0;
  totalSecondsLeft = TOTAL_TIME_SEC;
  perQSecondsLeft = PER_QUESTION_SEC;
  quizStarted = true;
  finalArea.innerHTML = '';
  navBtns.style.display = 'flex';
  restartBtn.style.display = 'none';
  statusInfo.textContent = '';
  renderCurrentQuestion();
  startTotalTimer();
  startPerQTimer();
}

/* Render current question */
function renderCurrentQuestion(){
  clearPerQTimer();
  perQSecondsLeft = PER_QUESTION_SEC;
  updateTimersUI();
  const qi = questionOrder[currentIdx];
  const item = baseQuestions[qi];
  const qNumber = currentIdx+1;
  qCounter.textContent = `Soal ${qNumber} / ${baseQuestions.length}`;
  progressBar.style.width = Math.round((currentIdx/baseQuestions.length)*100) + '%';
  quizArea.innerHTML = `
    <div class="question">Soal ${qNumber}. ${item.q}</div>
    <div class="choices" id="choices">${item.choices.map((c,idx)=>`<label><input type="radio" name="opt" value="${idx}"> <span>${String.fromCharCode(65+idx)}. ${c}</span></label>`).join('')}</div>
    <div id="feedback" class="feedback" aria-live="polite" style="display:none"></div>
  `;
  submitBtn.style.display = 'inline-block';
  nextBtn.style.display = 'none';
  restartBtn.style.display = 'none';
  // show skip button
  skipBtn.style.display = 'inline-block';
  // ensure listeners
  attachChoiceListeners();
  startPerQTimer();
}

/* Attach listener to choices to allow immediate selection styling (optional) */
function attachChoiceListeners(){
  const labels = quizArea.querySelectorAll('.choices label');
  labels.forEach(lbl=>{
    lbl.onclick = ()=> {
      // highlight selected label (simple)
      labels.forEach(l=> l.style.borderColor = 'transparent');
      lbl.style.borderColor = '#d1fae5';
    };
  });
}

/* Start total timer */
function startTotalTimer(){
  clearInterval(totalTimerInterval);
  totalTimerInterval = setInterval(()=>{
    totalSecondsLeft--;
    if(totalSecondsLeft < 0){
      clearInterval(totalTimerInterval);
      endQuizDueToTime();
      return;
    }
    updateTimersUI();
  },1000);
}

/* Start per-question timer */
function startPerQTimer(){
  clearPerQTimer();
  perQTimerInterval = setInterval(()=>{
    perQSecondsLeft--;
    if(perQSecondsLeft <= 0){
      clearPerQTimer();
      handleQuestionTimeout();
      return;
    }
    updateTimersUI();
  },1000);
}

/* Clear per question timer */
function clearPerQTimer(){ if(perQTimerInterval) { clearInterval(perQTimerInterval); perQTimerInterval = null; } }

/* Update timer displays */
function updateTimersUI(){
  totalTimerEl.textContent = formatTime(totalSecondsLeft);
  qTimerEl.textContent = formatTime(perQSecondsLeft);
}

/* Handle user submit answer */
submitBtn.addEventListener('click', ()=>{
  const opts = document.querySelectorAll('input[name="opt"]');
  let selected = null;
  opts.forEach(o=>{ if(o.checked) selected = parseInt(o.value); });
  if(selected === null){
    alert('Pilih jawaban dulu sebelum menekan Jawab, atau tekan "Lewati" untuk melewati soal.');
    return;
  }
  // disable choices
  opts.forEach(o=> o.disabled = true);
  submitBtn.style.display = 'none';
  nextBtn.style.display = 'inline-block';
  skipBtn.style.display = 'none';
  clearPerQTimer();

  const qi = questionOrder[currentIdx];
  const item = baseQuestions[qi];
  const isCorrect = (selected === item.a);
  const fb = document.getElementById('feedback');
  fb.style.display = 'block';
  if(isCorrect){
    fb.className = 'feedback correct';
    fb.innerHTML = `✅ Jawaban benar.<div class="explain">${item.explain}</div>`;
    score++;
  } else {
    fb.className = 'feedback wrong';
    fb.innerHTML = `❌ Jawaban salah. Jawaban benar: <strong>${String.fromCharCode(65+item.a)}. ${item.choices[item.a]}</strong>
      <div class="explain">${item.explain}</div>`;
  }
  answered++;
  nextBtn.textContent = (currentIdx === baseQuestions.length-1) ? 'Lihat Hasil' : 'Next →';
});

/* Handle skip */
skipBtn.addEventListener('click', ()=>{
  // treat as skipped: no score change, move to next
  clearPerQTimer();
  showSkipFeedbackThenNext();
});

/* When per-question time runs out */
function handleQuestionTimeout(){
  // per design: langsung pindah ke soal berikutnya tanpa memberi nilai
  showSkipFeedbackThenNext(true);
}

/* Show skip feedback, then auto advance after short pause */
function showSkipFeedbackThenNext(isTimeout=false){
  // disable submit/choices
  const opts = document.querySelectorAll('input[name="opt"]');
  opts.forEach(o=> o.disabled = true);
  submitBtn.style.display = 'none';
  nextBtn.style.display = 'inline-block';
  skipBtn.style.display = 'none';
  const qi = questionOrder[currentIdx];
  const item = baseQuestions[qi];
  const fb = document.getElementById('feedback');
  fb.style.display = 'block';
  fb.className = 'feedback skip';
  fb.innerHTML = isTimeout ?
    `⏱️ Waktu habis — soal dilewati. Jawaban tidak dinilai.` :
    `⏭️ Soal dilewati tanpa nilai.`;
  skipped++;
  // if last question, set button to show results
  nextBtn.textContent = (currentIdx === baseQuestions.length-1) ? 'Lihat Hasil' : 'Next →';
  // auto-advance after 1.2s if timeout, else wait for user to press next
  if(isTimeout){
    setTimeout(()=>{ 
      if(currentIdx === baseQuestions.length-1) { showResults(); }
      else { currentIdx++; renderCurrentQuestion(); }
    },1200);
  }
}

/* Next button */
nextBtn.addEventListener('click', ()=>{
  // if last question -> results
  if(currentIdx === baseQuestions.length-1){
    showResults();
    return;
  }
  currentIdx++;
  renderCurrentQuestion();
});

/* End quiz because total time ended */
function endQuizDueToTime(){
  // stop perQ timer
  clearPerQTimer();
  // show results immediately, mark remaining as skipped
  const remaining = baseQuestions.length - (currentIdx+1);
  skipped += Math.max(0, remaining);
  showResults(true);
}

/* Show results and review */
function showResults(timeUp=false){
  quizStarted = false;
  clearPerQTimer();
  clearInterval(totalTimerInterval);
  navBtns.style.display = 'none';
  progressBar.style.width = '100%';
  finalArea.innerHTML = '';
  const percent = Math.round((score / baseQuestions.length) * 100);
  const resBox = document.createElement('div');
  resBox.className = 'resultBox';
  resBox.innerHTML = `<h2>Hasil: ${score} / ${baseQuestions.length} (${percent}%)</h2>
    <p class="small">Answered: ${answered} • Skipped: ${skipped}</p>
    <p class="small">${ timeUp ? 'Waktu total habis — kuis dihentikan.' : '' }</p>
    <div style="margin-top:12px"><button id="restartBtn2">Ulangi Kuis</button></div>`;
  finalArea.appendChild(resBox);

  // detailed review
  const review = document.createElement('div');
  review.style.marginTop = '12px';
  review.innerHTML = '<h3>Review Soal</h3>';
  // show all questions with correct answers & explanations
  baseQuestions.forEach((it,idx)=>{
    const det = document.createElement('details');
    const sum = document.createElement('summary');
    sum.textContent = `Soal ${idx+1}: ${it.q}`;
    det.appendChild(sum);
    const body = document.createElement('div');
    body.style.padding = '8px';
    body.innerHTML = `<div><strong>Jawaban benar:</strong> ${String.fromCharCode(65+it.a)}. ${it.choices[it.a]}</div>
      <div class="explain" style="margin-top:6px">${it.explain}</div>`;
    det.appendChild(body);
    review.appendChild(det);
  });
  finalArea.appendChild(review);

  // show restart on top-right
  restartBtn.style.display = 'inline-block';
  restartBtn.textContent = 'Ulangi Kuis';
  // attach restart events
  document.getElementById('restartBtn2').addEventListener('click', ()=> { startQuiz(); });
  restartBtn.onclick = ()=> { startQuiz(); };
}

/* Restart button (top nav) */
document.getElementById('restartBtn').addEventListener('click', ()=> startQuiz());

/* Auto start on load */
startQuiz();

/* Also stop timers on page unload to be tidy */
window.addEventListener('beforeunload', ()=> { clearInterval(totalTimerInterval); clearPerQTimer(); });
</script>
</body>
</html>
Editor is loading...
Leave a Comment