"""Render QuizSet/FlashcardSet as self-contained interactive HTML.
All interactivity runs in the browser. ``"""
# ---------------------------------------------------------------------------
# Quiz (click-to-answer with instant feedback)
# ---------------------------------------------------------------------------
def render_quiz_html(quiz_set: QuizSet) -> str:
"""Return HTML with quiz data in ``data-quiz`` attribute for the MutationObserver."""
if not quiz_set.items:
return '
No questions available.
'
citation_map = {
citation.source_marker: {
"marker": citation.source_marker,
"filename": citation.filename,
"page": citation.page,
"text": citation.source_text or "",
}
for citation in quiz_set.citations
}
data = [
{
"q": item.question,
"opts": item.options,
"correct": item.correct_index,
"explanation": item.explanation or "No explanation provided.",
"difficulty": item.difficulty or "",
"sources": [
citation_map[marker]
for marker in item.source_markers
if marker in citation_map
],
}
for item in quiz_set.items
]
data_json = json.dumps(data, ensure_ascii=False)
scope_escaped = html_mod.escape(
f"{quiz_set.scope}: {quiz_set.target}" if quiz_set.target else quiz_set.scope
)
SVG_OK = (
''
)
SVG_BAD = (
''
)
return f"""
{scope_escaped}0 / {len(data)} answered
Mode1–4 answer · Enter next
Quiz complete
0
/ {len(data)}
Your Score
0% accuracy
{SVG_OK} 0 correct{SVG_BAD} 0 wrong
"""
# ---------------------------------------------------------------------------
# Flashcards (3D card flip with prev / next / shuffle)
# ---------------------------------------------------------------------------
def render_flashcard_html(flashcard_set: FlashcardSet) -> str:
"""Return HTML with flashcard data in ``data-cards`` attribute for the MutationObserver."""
if not flashcard_set.cards:
return '
No cards available.
'
citation_map = {
citation.source_marker: {
"marker": citation.source_marker,
"filename": citation.filename,
"page": citation.page,
"text": citation.source_text or "",
}
for citation in flashcard_set.citations
}
data = [
{
"front": card.front,
"back": card.back,
"hint": card.hint or "",
"sources": [
citation_map[marker]
for marker in card.source_markers
if marker in citation_map
],
}
for card in flashcard_set.cards
]
data_json = json.dumps(data, ensure_ascii=False)
scope_escaped = html_mod.escape(
f"{flashcard_set.scope}: {flashcard_set.target}"
if flashcard_set.target
else flashcard_set.scope
)
SVG_PREV = (
''
)
SVG_NEXT = (
''
)
SVG_SHUFFLE = (
''
)
return f"""