@0m0g1/griot 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/blocks/BlockRenderer.js +0 -142
package/package.json
CHANGED
|
@@ -476,148 +476,6 @@ function _renderQuiz(block, opts) {
|
|
|
476
476
|
return container;
|
|
477
477
|
}
|
|
478
478
|
|
|
479
|
-
function _renderQuiz(block, opts) {
|
|
480
|
-
const { meta = {} } = block;
|
|
481
|
-
const title = meta.title || '';
|
|
482
|
-
const questions = Array.isArray(meta.questions) ? meta.questions : [];
|
|
483
|
-
const answers = meta._submittedAnswers || {}; // optional: store last answers
|
|
484
|
-
|
|
485
|
-
const container = document.createElement('div');
|
|
486
|
-
container.className = 'griot-block griot-quiz';
|
|
487
|
-
|
|
488
|
-
if (title) {
|
|
489
|
-
const titleEl = document.createElement('h4');
|
|
490
|
-
titleEl.className = 'griot-quiz__title';
|
|
491
|
-
titleEl.textContent = title;
|
|
492
|
-
container.appendChild(titleEl);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
if (questions.length === 0) {
|
|
496
|
-
const empty = document.createElement('p');
|
|
497
|
-
empty.className = 'griot-quiz__empty';
|
|
498
|
-
empty.textContent = 'No questions yet.';
|
|
499
|
-
container.appendChild(empty);
|
|
500
|
-
return container;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
const form = document.createElement('form');
|
|
504
|
-
form.className = 'griot-quiz__form';
|
|
505
|
-
|
|
506
|
-
let totalScore = 0;
|
|
507
|
-
let userScore = 0;
|
|
508
|
-
|
|
509
|
-
questions.forEach((q, idx) => {
|
|
510
|
-
const qid = q.id || `q${idx}`;
|
|
511
|
-
const text = q.text || `Question ${idx + 1}`;
|
|
512
|
-
const options = Array.isArray(q.options) ? q.options : [];
|
|
513
|
-
const correctIdx = q.correctOption; // 0‑based index
|
|
514
|
-
const explanation = q.explanation || '';
|
|
515
|
-
const userChoice = answers[qid] !== undefined ? answers[qid] : null;
|
|
516
|
-
|
|
517
|
-
const fieldset = document.createElement('fieldset');
|
|
518
|
-
fieldset.className = 'griot-quiz__question';
|
|
519
|
-
fieldset.dataset.index = idx;
|
|
520
|
-
|
|
521
|
-
const legend = document.createElement('legend');
|
|
522
|
-
legend.className = 'griot-quiz__question-text';
|
|
523
|
-
legend.innerHTML = `<span class="griot-quiz__q-num">${idx + 1}.</span> ${escapeHtml(text)}`;
|
|
524
|
-
fieldset.appendChild(legend);
|
|
525
|
-
|
|
526
|
-
const optionsContainer = document.createElement('div');
|
|
527
|
-
optionsContainer.className = 'griot-quiz__options';
|
|
528
|
-
|
|
529
|
-
options.forEach((opt, optIdx) => {
|
|
530
|
-
const label = document.createElement('label');
|
|
531
|
-
label.className = 'griot-quiz__option';
|
|
532
|
-
|
|
533
|
-
const radio = document.createElement('input');
|
|
534
|
-
radio.type = 'radio';
|
|
535
|
-
radio.name = `quiz_${block.id}_${qid}`;
|
|
536
|
-
radio.value = optIdx;
|
|
537
|
-
if (userChoice === optIdx) radio.checked = true;
|
|
538
|
-
radio.addEventListener('change', () => {
|
|
539
|
-
// Update stored answers in meta (optional – allows preserving after submit)
|
|
540
|
-
const newAnswers = { ...(block.meta._submittedAnswers || {}), [qid]: optIdx };
|
|
541
|
-
// We'll trigger an external callback later – for now just store in meta
|
|
542
|
-
// But meta updates must go through the editor, not viewer. So we only calculate on‑the‑fly.
|
|
543
|
-
// Instead, we call a user callback when the quiz is submitted.
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
const span = document.createElement('span');
|
|
547
|
-
span.textContent = `${String.fromCharCode(65 + optIdx)}. ${escapeHtml(opt)}`;
|
|
548
|
-
|
|
549
|
-
label.appendChild(radio);
|
|
550
|
-
label.appendChild(span);
|
|
551
|
-
optionsContainer.appendChild(label);
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
fieldset.appendChild(optionsContainer);
|
|
555
|
-
|
|
556
|
-
// Show correct / wrong feedback after evaluation
|
|
557
|
-
const feedback = document.createElement('div');
|
|
558
|
-
feedback.className = 'griot-quiz__feedback';
|
|
559
|
-
fieldset.appendChild(feedback);
|
|
560
|
-
|
|
561
|
-
form.appendChild(fieldset);
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
const submitBtn = document.createElement('button');
|
|
565
|
-
submitBtn.type = 'button';
|
|
566
|
-
submitBtn.className = 'griot-quiz__submit';
|
|
567
|
-
submitBtn.textContent = 'Check answers';
|
|
568
|
-
submitBtn.addEventListener('click', () => {
|
|
569
|
-
let score = 0;
|
|
570
|
-
const newAnswers = {};
|
|
571
|
-
questions.forEach((q, idx) => {
|
|
572
|
-
const qid = q.id || `q${idx}`;
|
|
573
|
-
const radios = form.querySelectorAll(`input[name="quiz_${block.id}_${qid}"]`);
|
|
574
|
-
let selected = null;
|
|
575
|
-
radios.forEach((r, i) => { if (r.checked) selected = i; });
|
|
576
|
-
newAnswers[qid] = selected;
|
|
577
|
-
const isCorrect = (selected !== null && selected === q.correctOption);
|
|
578
|
-
if (isCorrect) score++;
|
|
579
|
-
|
|
580
|
-
// Show feedback per question
|
|
581
|
-
const feedbackDiv = form.querySelector(`fieldset[data-index="${idx}"] .griot-quiz__feedback`);
|
|
582
|
-
if (feedbackDiv) {
|
|
583
|
-
if (selected === null) {
|
|
584
|
-
feedbackDiv.textContent = '❓ No answer selected.';
|
|
585
|
-
feedbackDiv.className = 'griot-quiz__feedback griot-quiz__feedback--missing';
|
|
586
|
-
} else if (isCorrect) {
|
|
587
|
-
feedbackDiv.textContent = '✓ Correct!';
|
|
588
|
-
feedbackDiv.className = 'griot-quiz__feedback griot-quiz__feedback--correct';
|
|
589
|
-
} else {
|
|
590
|
-
const correctAnswerText = q.options[q.correctOption];
|
|
591
|
-
feedbackDiv.innerHTML = `✗ Incorrect. Correct answer: ${escapeHtml(correctAnswerText)}. ${escapeHtml(q.explanation || '')}`;
|
|
592
|
-
feedbackDiv.className = 'griot-quiz__feedback griot-quiz__feedback--wrong';
|
|
593
|
-
}
|
|
594
|
-
if (q.explanation && selected !== null && !isCorrect) {
|
|
595
|
-
// Already added above
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
});
|
|
599
|
-
totalScore = questions.length;
|
|
600
|
-
userScore = score;
|
|
601
|
-
|
|
602
|
-
// Display overall score
|
|
603
|
-
const existingScore = container.querySelector('.griot-quiz__score');
|
|
604
|
-
if (existingScore) existingScore.remove();
|
|
605
|
-
const scoreDiv = document.createElement('div');
|
|
606
|
-
scoreDiv.className = 'griot-quiz__score';
|
|
607
|
-
scoreDiv.textContent = `You scored ${score} out of ${totalScore}.`;
|
|
608
|
-
container.appendChild(scoreDiv);
|
|
609
|
-
|
|
610
|
-
// Fire user callback if provided
|
|
611
|
-
if (typeof opts.onQuizSubmit === 'function') {
|
|
612
|
-
opts.onQuizSubmit(block.id, score, totalScore, newAnswers);
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
form.appendChild(submitBtn);
|
|
617
|
-
container.appendChild(form);
|
|
618
|
-
return container;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
479
|
// ─── Embed URL helpers ────────────────────────────────────────────────────────
|
|
622
480
|
|
|
623
481
|
function _ytEmbed(src) {
|