@matinfo/vitepress-plugin-quiz 1.0.4 → 1.1.0
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/README.md +16 -0
- package/dist/src/types/quiz.d.ts +14 -2
- package/dist/src/utils.d.ts +5 -0
- package/dist/vitepress-plugin-quiz.js +457 -267
- package/dist/vitepress-plugin-quiz.js.map +1 -1
- package/dist/vitepress-plugin-quiz.umd.cjs +4 -4
- package/dist/vitepress-plugin-quiz.umd.cjs.map +1 -1
- package/package.json +29 -21
- package/dist/src/__tests__/locales.test.d.ts +0 -1
- package/dist/src/__tests__/mdPlugin.test.d.ts +0 -1
- package/dist/src/__tests__/richText.test.d.ts +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitepress-plugin-quiz.js","sources":["../src/styleManager.ts","../src/md-plugin.ts","../src/locales.ts","../src/utils.ts","../src/QuizQuestion.vue","../src/QuizPage.vue","../src/index.ts"],"sourcesContent":["import quizCssInline from \"./quiz.css?inline\"\n\nlet stylesInjected = false\n\nexport function ensureStylesInjected(): void {\n if (typeof document === \"undefined\") return\n if (stylesInjected) return\n const styleId = \"vitepress-plugin-quiz-styles\"\n if (document.getElementById(styleId)) {\n stylesInjected = true\n return\n }\n const style = document.createElement(\"style\")\n style.id = styleId\n style.textContent = quizCssInline\n document.head.appendChild(style)\n stylesInjected = true\n}\n","import type MarkdownIt from \"markdown-it\"\nimport type StateBlock from \"markdown-it/lib/rules_block/state_block.mjs\"\nimport type { QuizData, QuizAnswer } from \"./types/quiz\"\n\nconst QUIZ_RE = /^:::quiz\\s*$/\nconst CLOSE_RE = /^:::\\s*$/\n\n/**\n * Register the quiz block rule on a markdown-it instance.\n * Use in VitePress config:\n * markdown: { config(md) { md.use(quizMarkdownPlugin) } }\n */\nexport function quizMarkdownPlugin(md: MarkdownIt): void {\n const escapeHtml = md.utils.escapeHtml\n\n md.block.ruler.before(\n \"fence\",\n \"quiz\",\n (state, startLine, endLine, silent) =>\n quizBlockRule(state, startLine, endLine, silent, escapeHtml),\n { alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"] },\n )\n\n md.renderer.rules.quiz = (tokens, idx) => tokens[idx].content\n\n // Wrap entire token stream with <QuizPage>…</QuizPage> if quiz tokens exist\n md.core.ruler.push(\"quiz_page_wrap\", (state) => {\n const hasQuiz = state.tokens.some((t) => t.type === \"quiz\")\n if (!hasQuiz) return\n\n const open = new state.Token(\"html_block\", \"\", 0)\n open.content = \"<QuizPage>\\n\"\n open.block = true\n\n const close = new state.Token(\"html_block\", \"\", 0)\n close.content = \"</QuizPage>\\n\"\n close.block = true\n\n state.tokens.unshift(open)\n state.tokens.push(close)\n })\n}\n\n/* ── block rule ──────────────────────────────────────────────────────── */\n\nfunction quizBlockRule(\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n escapeHtml: (s: string) => string,\n): boolean {\n const startPos = state.bMarks[startLine] + state.tShift[startLine]\n const startMax = state.eMarks[startLine]\n const lineText = state.src.slice(startPos, startMax)\n\n if (!QUIZ_RE.test(lineText)) return false\n if (silent) return true\n\n let nextLine = startLine + 1\n let found = false\n while (nextLine < endLine) {\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\n const max = state.eMarks[nextLine]\n const line = state.src.slice(pos, max)\n if (CLOSE_RE.test(line)) {\n found = true\n break\n }\n nextLine++\n }\n if (!found) return false\n\n const innerLines: string[] = []\n for (let i = startLine + 1; i < nextLine; i++) {\n const pos = state.bMarks[i] + state.tShift[i]\n const max = state.eMarks[i]\n innerLines.push(state.src.slice(pos, max))\n }\n\n const data = parseQuizBlock(innerLines)\n if (!data) return false\n\n const token = state.push(\"quiz\", \"\", 0)\n token.content = renderQuizComponent(data, escapeHtml)\n token.map = [startLine, nextLine + 1]\n token.block = true\n\n state.line = nextLine + 1\n return true\n}\n\n/* ── parser ──────────────────────────────────────────────────────────── */\n\nexport function parseQuizBlock(lines: string[]): QuizData | null {\n let question = \"\"\n const answers: QuizAnswer[] = []\n let explanation = \"\"\n const expected: string[] = []\n let shuffle = false\n\n for (const raw of lines) {\n const line = raw.trim()\n if (!line) continue\n\n if (line.startsWith(\"question:\")) {\n question = line.slice(\"question:\".length).trim()\n } else if (line.startsWith(\"answer-correct:\")) {\n answers.push({ text: line.slice(\"answer-correct:\".length).trim(), correct: true })\n } else if (line.startsWith(\"answer-input:\")) {\n expected.push(line.slice(\"answer-input:\".length).trim())\n } else if (line.startsWith(\"answer:\")) {\n answers.push({ text: line.slice(\"answer:\".length).trim(), correct: false })\n } else if (line.startsWith(\"explanation:\")) {\n explanation = line.slice(\"explanation:\".length).trim()\n } else if (line.startsWith(\"explication:\")) {\n // legacy French alias\n explanation = line.slice(\"explication:\".length).trim()\n } else if (line.startsWith(\"shuffle:\")) {\n shuffle = line.slice(\"shuffle:\".length).trim().toLowerCase() === \"true\"\n }\n }\n\n if (!question) return null\n\n if (expected.length > 0) {\n return { question, type: \"input\", answers: [], expected, explanation, shuffle: false }\n }\n\n if (answers.length === 0) return null\n return { question, type: \"choice\", answers, expected: [], explanation, shuffle }\n}\n\n/* ── renderer ────────────────────────────────────────────────────────── */\n\nfunction renderQuizComponent(data: QuizData, escapeHtml: (s: string) => string): string {\n const json = JSON.stringify(data)\n const escaped = escapeHtml(json)\n return `<QuizQuestion data-quiz=\"${escaped}\" />\\n`\n}\n","import type { QuizLocale } from \"./types/quiz\"\n\nexport const locales: Record<string, QuizLocale> = {\n en: {\n answered: \"answered\",\n validate: \"Validate\",\n reset: \"Restart\",\n correctAnswers: (n) => `correct answer${n !== 1 ? \"s\" : \"\"}`,\n multipleHint: \"Multiple answers possible\",\n explanation: \"Explanation: \",\n inputHint: \"Type your answer\",\n inputPlaceholder: \"Your answer…\",\n expectedAnswer: \"Expected answer:\",\n },\n fr: {\n answered: \"répondue(s)\",\n validate: \"Valider\",\n reset: \"Recommencer\",\n correctAnswers: (n) => `réponse${n > 1 ? \"s\" : \"\"} correcte${n > 1 ? \"s\" : \"\"}`,\n multipleHint: \"Plusieurs réponses possibles\",\n explanation: \"Explication : \",\n inputHint: \"Saisissez votre réponse\",\n inputPlaceholder: \"Votre réponse…\",\n expectedAnswer: \"Réponse attendue :\",\n },\n de: {\n answered: \"beantwortet\",\n validate: \"Überprüfen\",\n reset: \"Neu starten\",\n correctAnswers: (n) => `richtige Antwort${n !== 1 ? \"en\" : \"\"}`,\n multipleHint: \"Mehrere Antworten möglich\",\n explanation: \"Erklärung:\",\n inputHint: \"Geben Sie Ihre Antwort ein\",\n inputPlaceholder: \"Ihre Antwort…\",\n expectedAnswer: \"Erwartete Antwort:\",\n },\n it: {\n answered: \"risposta/e\",\n validate: \"Verifica\",\n reset: \"Ricominciare\",\n correctAnswers: (n) => `rispost${n !== 1 ? \"e corrette\" : \"a corretta\"}`,\n multipleHint: \"Più risposte possibili\",\n explanation: \"Spiegazione: \",\n inputHint: \"Digita la tua risposta\",\n inputPlaceholder: \"La tua risposta…\",\n expectedAnswer: \"Risposta attesa:\",\n },\n es: {\n answered: \"respondida(s)\",\n validate: \"Validar\",\n reset: \"Reiniciar\",\n correctAnswers: (n) => `respuesta${n !== 1 ? \"s correctas\" : \" correcta\"}`,\n multipleHint: \"Varias respuestas posibles\",\n explanation: \"Explicación: \",\n inputHint: \"Escribe tu respuesta\",\n inputPlaceholder: \"Tu respuesta…\",\n expectedAnswer: \"Respuesta esperada:\",\n },\n}\n\n/**\n * Get locale strings for a given language code.\n * Falls back to English if the language is not found.\n */\nexport function getLocale(lang = \"en\"): QuizLocale {\n return locales[lang] ?? locales.en\n}\n","/**\n * Inline markdown part — result of {@link parseRichText}.\n */\nexport type RichPart = { type: \"text\" | \"bold\" | \"italic\" | \"code\"; value: string }\n\n/**\n * Parse inline markdown subsets: **bold**, *italic*, `code` → typed parts array.\n * Used for question titles, answer text, and explanations.\n */\nexport function parseRichText(text: string): RichPart[] {\n const parts: RichPart[] = []\n const re = /(\\*\\*(.+?)\\*\\*)|(\\*(.+?)\\*)|(`([^`]+)`)/g\n let last = 0\n let m\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) parts.push({ type: \"text\", value: text.slice(last, m.index) })\n if (m[2]) parts.push({ type: \"bold\", value: m[2] })\n else if (m[4]) parts.push({ type: \"italic\", value: m[4] })\n else if (m[6]) parts.push({ type: \"code\", value: m[6] })\n last = re.lastIndex\n }\n if (last < text.length) parts.push({ type: \"text\", value: text.slice(last) })\n return parts\n}\n","<script setup lang=\"ts\">\nimport { ref, computed, inject, watch, onMounted } from \"vue\"\nimport type { QuizData, QuizAnswer, QuizLocale, SavedAnswer } from \"./types/quiz\"\n\nconst props = defineProps({\n dataQuiz: { type: String, required: true },\n})\n\nconst rawQuiz = computed<QuizData | null>(() => {\n try {\n return JSON.parse(props.dataQuiz) as QuizData\n } catch {\n return null\n }\n})\n\n// Shuffle helper (Fisher-Yates)\nfunction shuffleArray<T>(arr: T[]): T[] {\n const a = [...arr]\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[a[i], a[j]] = [a[j], a[i]]\n }\n return a\n}\n\n// Shuffled answers — computed once at mount, re-shuffled on reset\nconst shuffledAnswers = ref<(QuizAnswer & { originalIndex: number })[]>([])\nfunction initAnswers() {\n if (!rawQuiz.value || rawQuiz.value.type === \"input\") {\n shuffledAnswers.value = []\n return\n }\n const indexed = rawQuiz.value.answers.map((a, i) => ({ ...a, originalIndex: i }))\n shuffledAnswers.value = rawQuiz.value.shuffle ? shuffleArray(indexed) : indexed\n}\n\n// Quiz data with shuffled answers\nconst quiz = computed(() => {\n if (!rawQuiz.value) return null\n return {\n ...rawQuiz.value,\n answers: shuffledAnswers.value,\n }\n})\n\nconst isInputMode = computed(() => rawQuiz.value?.type === 'input')\n\nconst correctCount = computed(() =>\n quiz.value && !isInputMode.value\n ? quiz.value.answers.filter((a) => a.correct).length\n : 0\n)\nconst isMultiple = computed(() => correctCount.value > 1)\n\n// Selected answer indices (for choice mode)\nconst selected = ref(new Set<number>())\n// Text input value (for fill-in-the-blank mode)\nconst inputValue = ref(\"\")\n\n// Registration with parent QuizPage\nconst register = inject<((q: { answered: typeof answered; isCorrect: typeof isCorrect }) => void) | null>(\"quiz-register\", null)\nconst validated = inject<ReturnType<typeof ref<boolean>>>(\"quiz-validated\", ref(false))\nconst resetCounter = inject<ReturnType<typeof ref<number>>>(\"quiz-reset\", ref(0))\nconst t = inject<QuizLocale>(\"quiz-locale\")!\n\n// Per-question persistence\nconst getQuestionId = inject<(() => number) | null>(\"quiz-question-id\", null)\nconst saveAnswer = inject<((id: number, data: SavedAnswer) => void) | null>(\"quiz-save-answer\", null)\nconst getAnswer = inject<((id: number) => SavedAnswer | null) | null>(\"quiz-get-answer\", null)\nconst myId: number | null = getQuestionId ? getQuestionId() : null\n\nconst answered = computed(() => {\n if (isInputMode.value) return inputValue.value.trim().length > 0\n return selected.value.size > 0\n})\n\nconst isCorrect = computed(() => {\n if (!quiz.value || !answered.value) return false\n\n if (isInputMode.value) {\n // Case-insensitive comparison against any accepted variant\n const input = inputValue.value.trim().toLowerCase()\n return rawQuiz.value!.expected.some((e) => input === e.trim().toLowerCase())\n }\n\n const correctIndices = new Set(\n quiz.value.answers\n .map((a, i) => (a.correct ? i : -1))\n .filter((i) => i >= 0)\n )\n if (selected.value.size !== correctIndices.size) return false\n for (const idx of selected.value) {\n if (!correctIndices.has(idx)) return false\n }\n return true\n})\n\n// Register this question with the parent page\nif (register) {\n register({ answered, isCorrect })\n}\n\n// Watch for reset from parent\nwatch(resetCounter, () => {\n selected.value = new Set()\n inputValue.value = ''\n initAnswers()\n})\n\nonMounted(() => {\n initAnswers()\n // Restore saved answer state\n if (getAnswer && myId !== null) {\n const saved = getAnswer(myId)\n if (saved) {\n if (saved.type === \"input\") {\n inputValue.value = saved.input\n } else if (saved.type === \"choice\") {\n selected.value = new Set(saved.selected)\n }\n }\n }\n})\n\nfunction toggle(idx: number) {\n if (validated.value) return\n const next = new Set(selected.value)\n if (isMultiple.value) {\n if (next.has(idx)) next.delete(idx)\n else next.add(idx)\n } else {\n next.clear()\n next.add(idx)\n }\n selected.value = next\n persistState()\n}\n\n// Save input value on change\nwatch(inputValue, () => {\n if (!validated.value) persistState()\n})\n\nfunction persistState() {\n if (!saveAnswer || myId === null) return\n if (isInputMode.value) {\n saveAnswer(myId, { type: \"input\", input: inputValue.value })\n } else {\n saveAnswer(myId, { type: \"choice\", selected: [...selected.value] })\n }\n}\n\nfunction answerClass(idx: number): string {\n if (!validated.value) {\n return selected.value.has(idx) ? \"quiz-answer selected\" : \"quiz-answer\"\n }\n const answer = quiz.value!.answers[idx]\n const wasPicked = selected.value.has(idx)\n if (answer.correct && wasPicked) return \"quiz-answer correct\"\n if (answer.correct && !wasPicked) return \"quiz-answer missed\"\n if (!answer.correct && wasPicked) return \"quiz-answer wrong\"\n return \"quiz-answer\"\n}\n\nconst inputClass = computed(() => {\n if (!validated.value) return \"quiz-input\"\n return isCorrect.value ? \"quiz-input correct\" : \"quiz-input wrong\"\n})\n\nimport { parseRichText, type RichPart } from './utils'\n</script>\n\n<template>\n <fieldset v-if=\"quiz\" class=\"quiz-question\" :class=\"{ validated: validated }\" :aria-label=\"quiz.question\">\n <legend class=\"quiz-question-title\">\n <template v-for=\"(part, pi) in parseRichText(quiz.question)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </legend>\n\n <!-- Choice mode -->\n <template v-if=\"!isInputMode\">\n <p v-if=\"isMultiple\" class=\"quiz-hint\">{{ t.multipleHint }}</p>\n <ul class=\"quiz-answers\" role=\"listbox\" :aria-multiselectable=\"isMultiple\">\n <li\n v-for=\"(answer, idx) in quiz.answers\"\n :key=\"answer.originalIndex\"\n :class=\"answerClass(idx)\"\n @click=\"toggle(idx)\"\n role=\"option\"\n :aria-selected=\"selected.has(idx)\"\n tabindex=\"0\"\n @keydown.enter=\"toggle(idx)\"\n @keydown.space.prevent=\"toggle(idx)\"\n >\n <span class=\"quiz-indicator\" aria-hidden=\"true\">\n <template v-if=\"isMultiple\">\n <span v-if=\"selected.has(idx)\" class=\"quiz-check\">✓</span>\n <span v-else class=\"quiz-empty\">☐</span>\n </template>\n <template v-else>\n <span v-if=\"selected.has(idx)\" class=\"quiz-check\">●</span>\n <span v-else class=\"quiz-empty\">○</span>\n </template>\n </span>\n <span class=\"quiz-answer-text\">\n <template v-for=\"(part, pi) in parseRichText(answer.text)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </span>\n </li>\n </ul>\n </template>\n\n <!-- Fill-in-the-blank mode -->\n <template v-if=\"isInputMode\">\n <p class=\"quiz-hint\">{{ t.inputHint }}</p>\n <div class=\"quiz-input-wrapper\">\n <input\n v-model=\"inputValue\"\n :class=\"inputClass\"\n type=\"text\"\n :disabled=\"validated\"\n :placeholder=\"t.inputPlaceholder\"\n :aria-label=\"quiz.question\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @keydown.enter.prevent\n />\n <p v-if=\"validated && !isCorrect\" class=\"quiz-expected\">\n {{ t.expectedAnswer }} <code>{{ rawQuiz?.expected[0] }}</code>\n </p>\n </div>\n </template>\n\n <!-- Explanation (rich text: supports **bold** and `code`) -->\n <div v-if=\"validated && quiz.explanation\" class=\"quiz-explanation\" role=\"note\">\n <strong>{{ t.explanation }}</strong>\n <template v-for=\"(part, pi) in parseRichText(quiz.explanation)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </div>\n </fieldset>\n</template>\n","<script setup lang=\"ts\">\nimport { ref, computed, provide, inject } from \"vue\"\nimport type { QuizLocale, QuizState, SavedAnswer } from \"./types/quiz\"\n\nconst t = inject<QuizLocale>(\"quiz-locale\")!\nconst questions = ref<QuizState[]>([])\nconst validated = ref(false)\n\n// Generate a storage key from the page path — set eagerly so children can read on mount\n// (Vue mounts children before parent, so onMounted would be too late)\nconst storageKey = typeof window !== 'undefined'\n ? 'quiz-state:' + window.location.pathname\n : ''\n\n// Restore quiz-level state immediately so validated is set before children mount\nrestoreState()\n\n// Question index counter for stable per-question storage keys\nlet questionIdx = 0\n\nprovide(\"quiz-validated\", validated)\nprovide(\"quiz-register\", (q: QuizState) => {\n questions.value.push(q)\n})\n\n// Per-question persistence: each question gets a unique sub-key\nprovide(\"quiz-question-id\", () => questionIdx++)\nprovide(\"quiz-save-answer\", (qId: number, data: SavedAnswer) => {\n if (!storageKey) return\n try {\n sessionStorage.setItem(storageKey + \":q\" + qId, JSON.stringify(data))\n } catch { /* ignore */ }\n})\nprovide(\"quiz-get-answer\", (qId: number): SavedAnswer | null => {\n if (!storageKey) return null\n try {\n const raw = sessionStorage.getItem(storageKey + \":q\" + qId)\n return raw ? JSON.parse(raw) : null\n } catch { return null }\n})\n\n// Provide a reset trigger for child components\nconst resetCounter = ref(0)\nprovide(\"quiz-reset\", resetCounter)\n\nconst totalQuestions = computed(() => questions.value.length)\nconst answeredCount = computed(() =>\n questions.value.filter((q) => q.answered).length\n)\nconst correctCount = computed(() =>\n questions.value.filter((q) => q.isCorrect).length\n)\nconst allAnswered = computed(() => answeredCount.value === totalQuestions.value)\nconst progressPct = computed(() =>\n totalQuestions.value ? Math.round((answeredCount.value / totalQuestions.value) * 100) : 0\n)\n\nfunction validate() {\n validated.value = true\n saveState()\n}\n\nfunction reset() {\n validated.value = false\n resetCounter.value++\n clearState()\n}\n\n/* ── sessionStorage persistence ───────────────────────────────────── */\nfunction saveState() {\n if (!storageKey) return\n try {\n const data = { validated: validated.value, ts: Date.now() }\n sessionStorage.setItem(storageKey, JSON.stringify(data))\n } catch { /* storage full or unavailable */ }\n}\n\nfunction restoreState() {\n if (!storageKey) return\n try {\n const raw = sessionStorage.getItem(storageKey)\n if (!raw) return\n const data = JSON.parse(raw)\n if (data && data.validated) {\n validated.value = true\n }\n } catch { /* corrupted – ignore */ }\n}\n\nfunction clearState() {\n if (!storageKey) return\n try {\n const keysToRemove: string[] = []\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i)\n if (key && key.startsWith(storageKey)) {\n keysToRemove.push(key)\n }\n }\n keysToRemove.forEach((k) => sessionStorage.removeItem(k))\n } catch { /* ignore */ }\n}\n</script>\n\n<template>\n <div class=\"quiz-page\" role=\"region\" aria-label=\"Quiz\">\n <div\nclass=\"quiz-progress-bar\" role=\"progressbar\"\n :aria-valuenow=\"answeredCount\"\n :aria-valuemin=\"0\"\n :aria-valuemax=\"totalQuestions\"\n :aria-label=\"answeredCount + ' / ' + totalQuestions + ' ' + t.answered\"\n >\n <div class=\"quiz-progress-track\">\n <div\n class=\"quiz-progress-fill\"\n :style=\"{ width: progressPct + '%' }\"\n :class=\"{ complete: progressPct === 100 }\"\n ></div>\n </div>\n <span class=\"quiz-progress-label\" aria-live=\"polite\">\n {{ answeredCount }} / {{ totalQuestions }} {{ t.answered }}\n </span>\n </div>\n\n <slot />\n\n <div class=\"quiz-actions\">\n <button\n v-if=\"!validated\"\n class=\"quiz-btn quiz-btn-validate\"\n :disabled=\"!allAnswered\"\n @click=\"validate\"\n >\n {{ t.validate }}\n </button>\n\n <template v-if=\"validated\">\n <div\nclass=\"quiz-score\" role=\"status\" aria-live=\"polite\"\n :aria-label=\"correctCount + ' / ' + totalQuestions + ' ' + t.correctAnswers(correctCount)\"\n >\n <span class=\"quiz-score-value\">{{ correctCount }} / {{ totalQuestions }}</span>\n <span class=\"quiz-score-label\">\n {{ t.correctAnswers(correctCount) }}\n ({{ totalQuestions ? Math.round((correctCount / totalQuestions) * 100) : 0 }}%)\n </span>\n </div>\n <button class=\"quiz-btn quiz-btn-reset\" @click=\"reset\">\n {{ t.reset }}\n </button>\n </template>\n </div>\n </div>\n</template>\n","import type { App } from \"vue\"\nimport { ensureStylesInjected } from \"./styleManager\"\n\nexport { quizMarkdownPlugin } from \"./md-plugin\"\nexport { getLocale, locales } from \"./locales\"\nexport type { QuizData, QuizAnswer, QuizLocale, QuizState, SavedAnswer } from \"./types/quiz\"\n\nimport QuizQuestion from \"./QuizQuestion.vue\"\nimport QuizPage from \"./QuizPage.vue\"\nimport { getLocale as _getLocale } from \"./locales\"\n\nexport { QuizQuestion, QuizPage }\n\n/**\n * Register quiz components and locale in a VitePress `enhanceApp` hook.\n *\n * @example\n * // .vitepress/theme/index.ts\n * import { enhanceAppWithQuiz } from '@matinfo/vitepress-plugin-quiz'\n * export default {\n * enhanceApp({ app }) {\n * enhanceAppWithQuiz(app) // English (default)\n * enhanceAppWithQuiz(app, 'fr') // French\n * }\n * }\n */\nexport function enhanceAppWithQuiz(app: App, lang = \"en\"): void {\n ensureStylesInjected()\n app.provide(\"quiz-locale\", _getLocale(lang))\n app.component(\"QuizQuestion\", QuizQuestion)\n app.component(\"QuizPage\", QuizPage)\n}\n"],"names":["stylesInjected","ensureStylesInjected","styleId","style","quizCssInline","QUIZ_RE","CLOSE_RE","quizMarkdownPlugin","md","escapeHtml","state","startLine","endLine","silent","quizBlockRule","tokens","idx","t","open","close","startPos","startMax","lineText","nextLine","found","pos","max","line","innerLines","i","data","parseQuizBlock","token","renderQuizComponent","lines","question","answers","explanation","expected","shuffle","raw","json","locales","n","getLocale","lang","parseRichText","text","parts","re","last","m","props","__props","rawQuiz","computed","shuffleArray","arr","a","j","shuffledAnswers","ref","initAnswers","indexed","quiz","isInputMode","correctCount","isMultiple","selected","inputValue","register","inject","validated","resetCounter","getQuestionId","saveAnswer","getAnswer","myId","answered","isCorrect","input","e","correctIndices","watch","onMounted","saved","toggle","next","persistState","answerClass","answer","wasPicked","inputClass","_createElementBlock","_normalizeClass","_unref","_createElementVNode","_hoisted_2","_Fragment","_renderList","part","pi","_hoisted_3","_toDisplayString","_hoisted_4","_hoisted_5","_createTextVNode","_openBlock","_hoisted_6","$event","_withKeys","_withModifiers","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","questions","storageKey","restoreState","questionIdx","provide","q","qId","totalQuestions","answeredCount","allAnswered","progressPct","validate","saveState","reset","clearState","keysToRemove","key","k","_hoisted_1","_renderSlot","_ctx","_hoisted_8","enhanceAppWithQuiz","app","_getLocale","QuizQuestion","QuizPage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vitepress-plugin-quiz.js","sources":["../src/styleManager.ts","../src/md-plugin.ts","../src/locales.ts","../src/utils.ts","../src/QuizQuestion.vue","../src/QuizPage.vue","../src/index.ts"],"sourcesContent":["import quizCssInline from \"./quiz.css?inline\"\n\nlet stylesInjected = false\n\nexport function ensureStylesInjected(): void {\n if (typeof document === \"undefined\") return\n if (stylesInjected) return\n const styleId = \"vitepress-plugin-quiz-styles\"\n if (document.getElementById(styleId)) {\n stylesInjected = true\n return\n }\n const style = document.createElement(\"style\")\n style.id = styleId\n style.textContent = quizCssInline\n document.head.appendChild(style)\n stylesInjected = true\n}\n","import type MarkdownIt from \"markdown-it\"\nimport type StateBlock from \"markdown-it/lib/rules_block/state_block.mjs\"\nimport type { QuizData, QuizAnswer, QuizPair } from \"./types/quiz\"\n\nconst QUIZ_RE = /^:::quiz\\s*$/\nconst CLOSE_RE = /^:::\\s*$/\nconst KEY_RE = /^([A-Za-z-]+):(.*)$/\nconst KNOWN_KEYS = new Set([\n \"question\",\n \"answer\",\n \"answer-correct\",\n \"answer-input\",\n \"pair\",\n \"distractor\",\n \"explanation\",\n \"explication\",\n \"shuffle\",\n])\n\n/**\n * Register the quiz block rule on a markdown-it instance.\n * Use in VitePress config:\n * markdown: { config(md) { md.use(quizMarkdownPlugin) } }\n */\nexport function quizMarkdownPlugin(md: MarkdownIt): void {\n const escapeHtml = md.utils.escapeHtml\n\n md.block.ruler.before(\n \"fence\",\n \"quiz\",\n (state, startLine, endLine, silent) =>\n quizBlockRule(state, startLine, endLine, silent, escapeHtml),\n { alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"] },\n )\n\n md.renderer.rules.quiz = (tokens, idx) => tokens[idx].content\n\n // Wrap entire token stream with <QuizPage>…</QuizPage> if quiz tokens exist\n md.core.ruler.push(\"quiz_page_wrap\", (state) => {\n const hasQuiz = state.tokens.some((t) => t.type === \"quiz\")\n if (!hasQuiz) return\n\n const open = new state.Token(\"html_block\", \"\", 0)\n open.content = \"<QuizPage>\\n\"\n open.block = true\n\n const close = new state.Token(\"html_block\", \"\", 0)\n close.content = \"</QuizPage>\\n\"\n close.block = true\n\n state.tokens.unshift(open)\n state.tokens.push(close)\n })\n}\n\n/* ── block rule ──────────────────────────────────────────────────────── */\n\nfunction quizBlockRule(\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n escapeHtml: (s: string) => string,\n): boolean {\n // 4+ spaces of indentation is an indented code block, not a quiz\n if (state.sCount[startLine] - state.blkIndent >= 4) return false\n\n const startPos = state.bMarks[startLine] + state.tShift[startLine]\n const startMax = state.eMarks[startLine]\n const lineText = state.src.slice(startPos, startMax)\n\n if (!QUIZ_RE.test(lineText)) return false\n if (silent) return true\n\n let nextLine = startLine + 1\n let found = false\n while (nextLine < endLine) {\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\n const max = state.eMarks[nextLine]\n const line = state.src.slice(pos, max)\n if (CLOSE_RE.test(line)) {\n found = true\n break\n }\n nextLine++\n }\n if (!found) return false\n\n const innerLines: string[] = []\n for (let i = startLine + 1; i < nextLine; i++) {\n const pos = state.bMarks[i] + state.tShift[i]\n const max = state.eMarks[i]\n innerLines.push(state.src.slice(pos, max))\n }\n\n const data = parseQuizBlock(innerLines)\n if (data?.type === \"choice\" && !data.answers.some((a) => a.correct)) {\n console.warn(\n `[vitepress-plugin-quiz] :quiz block at line ${startLine + 1} has no 'answer-correct:'; ` +\n \"it can never be answered correctly.\",\n )\n }\n if (!data) {\n console.warn(\n `[vitepress-plugin-quiz] Ignored invalid :::quiz block at line ${startLine + 1}: ` +\n \"needs a 'question:' and at least one 'answer:'/'answer-correct:', 'answer-input:', or two 'pair: A => B' lines.\",\n )\n return false\n }\n\n const token = state.push(\"quiz\", \"\", 0)\n token.content = renderQuizComponent(data, escapeHtml)\n token.map = [startLine, nextLine + 1]\n token.block = true\n\n state.line = nextLine + 1\n return true\n}\n\n/* ── parser ──────────────────────────────────────────────────────────── */\n\nexport function parseQuizBlock(lines: string[]): QuizData | null {\n let question = \"\"\n const answers: QuizAnswer[] = []\n let explanation = \"\"\n const expected: string[] = []\n const pairs: QuizPair[] = []\n const distractors: string[] = []\n let shuffle = false\n\n // Lines that are not a known `key:` continue the previous field (multi-line values).\n let append: ((extra: string) => void) | null = null\n\n for (const raw of lines) {\n const line = raw.trim()\n if (!line) continue\n\n const m = KEY_RE.exec(line)\n const key = m?.[1].toLowerCase()\n if (!m || !key || !KNOWN_KEYS.has(key)) {\n append?.(line)\n continue\n }\n const value = m[2].trim()\n const join = (cur: string, extra: string) => (cur ? `${cur} ${extra}` : extra)\n\n switch (key) {\n case \"question\":\n question = value\n append = (x) => (question = join(question, x))\n break\n case \"answer-correct\":\n case \"answer\": {\n const entry: QuizAnswer = { text: value, correct: key === \"answer-correct\" }\n answers.push(entry)\n append = (x) => (entry.text = join(entry.text, x))\n break\n }\n case \"answer-input\":\n if (value) expected.push(value)\n append = null\n break\n case \"pair\": {\n // `=>` wins; `-->` is an alias\n let sep = value.indexOf(\"=>\")\n let sepLen = 2\n if (sep < 0) {\n sep = value.indexOf(\"-->\")\n sepLen = 3\n }\n if (sep < 0) {\n console.warn(`[vitepress-plugin-quiz] Ignored 'pair:' without '=>' or '-->': \"${value}\"`)\n append = null\n break\n }\n const entry: QuizPair = {\n left: value.slice(0, sep).trim(),\n right: value.slice(sep + sepLen).trim(),\n }\n if (entry.left && entry.right) pairs.push(entry)\n append = null\n break\n }\n case \"distractor\":\n if (value) distractors.push(value)\n append = null\n break\n case \"explanation\":\n case \"explication\": // legacy French alias\n explanation = value\n append = (x) => (explanation = join(explanation, x))\n break\n case \"shuffle\":\n shuffle = value.toLowerCase() === \"true\"\n append = null\n break\n }\n }\n\n if (!question) return null\n\n if (expected.length > 0) {\n return {\n question, type: \"input\", answers: [], expected, pairs: [], options: [],\n explanation, shuffle: false,\n }\n }\n\n if (pairs.length >= 2) {\n const options = [...new Set([...pairs.map((p) => p.right), ...distractors])]\n return {\n question, type: \"association\", answers: [], expected: [], pairs, options,\n explanation, shuffle,\n }\n }\n\n if (answers.length === 0) return null\n return {\n question, type: \"choice\", answers, expected: [], pairs: [], options: [],\n explanation, shuffle,\n }\n}\n\n/* ── renderer ────────────────────────────────────────────────────────── */\n\nfunction renderQuizComponent(data: QuizData, escapeHtml: (s: string) => string): string {\n const json = JSON.stringify(data)\n const escaped = escapeHtml(json)\n return `<QuizQuestion data-quiz=\"${escaped}\" />\\n`\n}\n","import type { QuizLocale } from \"./types/quiz\"\n\nexport const locales: Record<string, QuizLocale> = {\n en: {\n answered: \"answered\",\n validate: \"Validate\",\n reset: \"Restart\",\n correctAnswers: (n) => `correct answer${n !== 1 ? \"s\" : \"\"}`,\n multipleHint: \"Multiple answers possible\",\n explanation: \"Explanation: \",\n inputHint: \"Type your answer\",\n inputPlaceholder: \"Your answer…\",\n expectedAnswer: \"Expected answer:\",\n associationHint: \"Match each item with its answer\",\n associationPlaceholder: \"Choose…\",\n },\n fr: {\n answered: \"répondue(s)\",\n validate: \"Valider\",\n reset: \"Recommencer\",\n correctAnswers: (n) => `réponse${n > 1 ? \"s\" : \"\"} correcte${n > 1 ? \"s\" : \"\"}`,\n multipleHint: \"Plusieurs réponses possibles\",\n explanation: \"Explication : \",\n inputHint: \"Saisissez votre réponse\",\n inputPlaceholder: \"Votre réponse…\",\n expectedAnswer: \"Réponse attendue :\",\n associationHint: \"Associez chaque élément à sa réponse\",\n associationPlaceholder: \"Choisir…\",\n },\n de: {\n answered: \"beantwortet\",\n validate: \"Überprüfen\",\n reset: \"Neu starten\",\n correctAnswers: (n) => `richtige Antwort${n !== 1 ? \"en\" : \"\"}`,\n multipleHint: \"Mehrere Antworten möglich\",\n explanation: \"Erklärung:\",\n inputHint: \"Geben Sie Ihre Antwort ein\",\n inputPlaceholder: \"Ihre Antwort…\",\n expectedAnswer: \"Erwartete Antwort:\",\n associationHint: \"Ordnen Sie jedem Element die passende Antwort zu\",\n associationPlaceholder: \"Auswählen…\",\n },\n it: {\n answered: \"risposta/e\",\n validate: \"Verifica\",\n reset: \"Ricominciare\",\n correctAnswers: (n) => `rispost${n !== 1 ? \"e corrette\" : \"a corretta\"}`,\n multipleHint: \"Più risposte possibili\",\n explanation: \"Spiegazione: \",\n inputHint: \"Digita la tua risposta\",\n inputPlaceholder: \"La tua risposta…\",\n expectedAnswer: \"Risposta attesa:\",\n associationHint: \"Abbina ogni elemento alla risposta corretta\",\n associationPlaceholder: \"Scegli…\",\n },\n es: {\n answered: \"respondida(s)\",\n validate: \"Validar\",\n reset: \"Reiniciar\",\n correctAnswers: (n) => `respuesta${n !== 1 ? \"s correctas\" : \" correcta\"}`,\n multipleHint: \"Varias respuestas posibles\",\n explanation: \"Explicación: \",\n inputHint: \"Escribe tu respuesta\",\n inputPlaceholder: \"Tu respuesta…\",\n expectedAnswer: \"Respuesta esperada:\",\n associationHint: \"Asocia cada elemento con su respuesta\",\n associationPlaceholder: \"Elegir…\",\n },\n}\n\n/**\n * Get locale strings for a given language code.\n * Falls back to English if the language is not found.\n */\nexport function getLocale(lang = \"en\"): QuizLocale {\n return locales[lang] ?? locales.en\n}\n","/**\n * Inline markdown part — result of {@link parseRichText}.\n */\nexport type RichPart = { type: \"text\" | \"bold\" | \"italic\" | \"code\"; value: string }\n\n/**\n * Parse inline markdown subsets: **bold**, *italic*, `code` → typed parts array.\n * Used for question titles, answer text, and explanations.\n */\nexport function parseRichText(text: string): RichPart[] {\n const parts: RichPart[] = []\n const re = /(\\*\\*(?!\\s)(.+?)\\*\\*)|(\\*(?!\\s)(.+?)(?<!\\s)\\*)|(`([^`]+)`)/g\n let last = 0\n let m\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) parts.push({ type: \"text\", value: text.slice(last, m.index) })\n if (m[2]) parts.push({ type: \"bold\", value: m[2] })\n else if (m[4]) parts.push({ type: \"italic\", value: m[4] })\n else if (m[6]) parts.push({ type: \"code\", value: m[6] })\n last = re.lastIndex\n }\n if (last < text.length) parts.push({ type: \"text\", value: text.slice(last) })\n return parts\n}\n\n/**\n * Normalise a typed answer for lenient comparison: case-insensitive,\n * accent-insensitive (\"Réseau\" == \"reseau\"), trimmed, whitespace collapsed.\n */\nexport function normalizeInput(text: string): string {\n return text\n .normalize(\"NFD\")\n .replace(/\\p{M}/gu, \"\")\n .trim()\n .replace(/\\s+/g, \" \")\n .toLowerCase()\n}\n","<script setup lang=\"ts\">\nimport { ref, computed, inject, watch, onMounted, onUnmounted } from \"vue\"\nimport type { QuizData, QuizAnswer, QuizLocale, SavedAnswer } from \"./types/quiz\"\n\nconst props = defineProps({\n dataQuiz: { type: String, required: true },\n})\n\nconst rawQuiz = computed<QuizData | null>(() => {\n try {\n return JSON.parse(props.dataQuiz) as QuizData\n } catch {\n return null\n }\n})\n\n// Shuffle helper (Fisher-Yates)\nfunction shuffleArray<T>(arr: T[]): T[] {\n const a = [...arr]\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[a[i], a[j]] = [a[j], a[i]]\n }\n return a\n}\n\n// Shuffled answers — computed once at mount, re-shuffled on reset\nconst shuffledAnswers = ref<(QuizAnswer & { originalIndex: number })[]>([])\nfunction initAnswers() {\n if (!rawQuiz.value || rawQuiz.value.type !== \"choice\") {\n shuffledAnswers.value = []\n return\n }\n const indexed = rawQuiz.value.answers.map((a, i) => ({ ...a, originalIndex: i }))\n shuffledAnswers.value = rawQuiz.value.shuffle ? shuffleArray(indexed) : indexed\n}\n\n// Quiz data with shuffled answers\nconst quiz = computed(() => {\n if (!rawQuiz.value) return null\n return {\n ...rawQuiz.value,\n answers: shuffledAnswers.value,\n }\n})\n\nconst isInputMode = computed(() => rawQuiz.value?.type === 'input')\nconst isAssociation = computed(() => rawQuiz.value?.type === 'association')\n\nconst correctCount = computed(() =>\n quiz.value && !isInputMode.value && !isAssociation.value\n ? quiz.value.answers.filter((a) => a.correct).length\n : 0\n)\nconst isMultiple = computed(() => correctCount.value > 1)\n\n// Selected answers, by ORIGINAL index (stable across shuffles and reloads)\nconst selected = ref(new Set<number>())\n// Association: chosen option index (into rawQuiz.options) per pair row, null = empty\nconst chosen = ref<(number | null)[]>([])\n// Association: option display order (original option indices)\nconst optionOrder = ref<number[]>([])\nfunction initAssociation() {\n const q = rawQuiz.value\n if (!q || q.type !== \"association\") {\n chosen.value = []\n optionOrder.value = []\n return\n }\n chosen.value = q.pairs.map(() => null)\n const order = q.options.map((_, i) => i)\n optionOrder.value = q.shuffle ? shuffleArray(order) : order\n}\n// Text input value (for fill-in-the-blank mode)\nconst inputValue = ref(\"\")\n\n// Registration with parent QuizPage\nconst register = inject<((q: { answered: typeof answered; isCorrect: typeof isCorrect }) => () => void) | null>(\"quiz-register\", null)\nconst validated = inject<ReturnType<typeof ref<boolean>>>(\"quiz-validated\", ref(false))\nconst resetCounter = inject<ReturnType<typeof ref<number>>>(\"quiz-reset\", ref(0))\nconst t = inject<QuizLocale>(\"quiz-locale\")!\n\n// Per-question persistence\nconst getQuestionId = inject<(() => number) | null>(\"quiz-question-id\", null)\nconst saveAnswer = inject<((id: number, data: SavedAnswer) => void) | null>(\"quiz-save-answer\", null)\nconst getAnswer = inject<((id: number) => SavedAnswer | null) | null>(\"quiz-get-answer\", null)\nconst myId: number | null = getQuestionId ? getQuestionId() : null\n\nconst answered = computed(() => {\n if (isAssociation.value) {\n return chosen.value.length > 0 && chosen.value.every((c) => c !== null)\n }\n if (isInputMode.value) return inputValue.value.trim().length > 0\n return selected.value.size > 0\n})\n\nconst isCorrect = computed(() => {\n if (!quiz.value || !answered.value) return false\n\n if (isInputMode.value) {\n // Case-insensitive comparison against any accepted variant\n const input = normalizeInput(inputValue.value)\n return rawQuiz.value!.expected.some((e) => input === normalizeInput(e))\n }\n\n if (isAssociation.value) {\n return rawQuiz.value!.pairs.every((_, i) => rowCorrect(i))\n }\n\n const correctIndices = new Set(\n rawQuiz.value!.answers\n .map((a, i) => (a.correct ? i : -1))\n .filter((i) => i >= 0)\n )\n if (selected.value.size !== correctIndices.size) return false\n for (const idx of selected.value) {\n if (!correctIndices.has(idx)) return false\n }\n return true\n})\n\nfunction rowCorrect(i: number): boolean {\n const q = rawQuiz.value\n const c = chosen.value[i]\n if (!q || c === null || c === undefined) return false\n return q.options[c] === q.pairs[i].right\n}\n\n// Register this question with the parent page\nif (register && rawQuiz.value) {\n const unregister = register({ answered, isCorrect })\n onUnmounted(unregister)\n}\n\n// Watch for reset from parent\nwatch(resetCounter, () => {\n selected.value = new Set()\n inputValue.value = ''\n initAnswers()\n initAssociation()\n})\n\nonMounted(() => {\n initAnswers()\n initAssociation()\n // Restore saved answer state\n if (getAnswer && myId !== null) {\n const saved = getAnswer(myId)\n if (saved) {\n if (saved.type === \"input\" && isInputMode.value && typeof saved.input === \"string\") {\n inputValue.value = saved.input\n } else if (saved.type === \"association\" && isAssociation.value && Array.isArray(saved.chosen)) {\n const max = rawQuiz.value?.options.length ?? 0\n chosen.value = chosen.value.map((_, i) => {\n const v = saved.chosen[i]\n return typeof v === \"number\" && Number.isInteger(v) && v >= 0 && v < max ? v : null\n })\n } else if (saved.type === \"choice\" && !isAssociation.value && !isInputMode.value && Array.isArray(saved.selected)) {\n const max = rawQuiz.value?.answers.length ?? 0\n selected.value = new Set(\n saved.selected.filter((i) => Number.isInteger(i) && i >= 0 && i < max),\n )\n }\n }\n }\n})\n\nfunction onSelect(row: number, event: Event) {\n if (validated.value) return\n const v = (event.target as HTMLSelectElement).value\n const next = [...chosen.value]\n next[row] = v === \"\" ? null : Number(v)\n chosen.value = next\n persistState()\n}\n\nfunction toggle(orig: number) {\n if (validated.value) return\n const next = new Set(selected.value)\n if (isMultiple.value) {\n if (next.has(orig)) next.delete(orig)\n else next.add(orig)\n } else {\n next.clear()\n next.add(orig)\n }\n selected.value = next\n persistState()\n}\n\n// Save input value on change\nwatch(inputValue, () => {\n if (!validated.value) persistState()\n})\n\nfunction persistState() {\n if (!saveAnswer || myId === null) return\n if (isAssociation.value) {\n saveAnswer(myId, { type: \"association\", chosen: [...chosen.value] })\n } else if (isInputMode.value) {\n saveAnswer(myId, { type: \"input\", input: inputValue.value })\n } else {\n saveAnswer(myId, { type: \"choice\", selected: [...selected.value] })\n }\n}\n\nfunction answerClass(answer: QuizAnswer & { originalIndex: number }): string {\n const wasPicked = selected.value.has(answer.originalIndex)\n if (!validated.value) {\n return wasPicked ? \"quiz-answer selected\" : \"quiz-answer\"\n }\n if (answer.correct && wasPicked) return \"quiz-answer correct\"\n if (answer.correct && !wasPicked) return \"quiz-answer missed\"\n if (!answer.correct && wasPicked) return \"quiz-answer wrong\"\n return \"quiz-answer\"\n}\n\nfunction rowClass(i: number): string {\n if (!validated.value) return \"quiz-assoc-select\"\n return rowCorrect(i) ? \"quiz-assoc-select correct\" : \"quiz-assoc-select wrong\"\n}\n\nconst inputClass = computed(() => {\n if (!validated.value) return \"quiz-input\"\n return isCorrect.value ? \"quiz-input correct\" : \"quiz-input wrong\"\n})\n\nimport { parseRichText, normalizeInput } from './utils'\n</script>\n\n<template>\n <fieldset v-if=\"quiz\" class=\"quiz-question\" :class=\"{ validated: validated }\" :aria-label=\"quiz.question\">\n <legend class=\"quiz-question-title\">\n <template v-for=\"(part, pi) in parseRichText(quiz.question)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </legend>\n\n <!-- Choice mode -->\n <template v-if=\"!isInputMode && !isAssociation\">\n <p v-if=\"isMultiple\" class=\"quiz-hint\">{{ t.multipleHint }}</p>\n <ul class=\"quiz-answers\" role=\"listbox\" :aria-multiselectable=\"isMultiple\">\n <li\n v-for=\"answer in quiz.answers\"\n :key=\"answer.originalIndex\"\n :class=\"answerClass(answer)\"\n @click=\"toggle(answer.originalIndex)\"\n role=\"option\"\n :aria-selected=\"selected.has(answer.originalIndex)\"\n tabindex=\"0\"\n @keydown.enter=\"toggle(answer.originalIndex)\"\n @keydown.space.prevent=\"toggle(answer.originalIndex)\"\n >\n <span class=\"quiz-indicator\" aria-hidden=\"true\">\n <template v-if=\"isMultiple\">\n <span v-if=\"selected.has(answer.originalIndex)\" class=\"quiz-check\">✓</span>\n <span v-else class=\"quiz-empty\">☐</span>\n </template>\n <template v-else>\n <span v-if=\"selected.has(answer.originalIndex)\" class=\"quiz-check\">●</span>\n <span v-else class=\"quiz-empty\">○</span>\n </template>\n </span>\n <span class=\"quiz-answer-text\">\n <template v-for=\"(part, pi) in parseRichText(answer.text)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </span>\n </li>\n </ul>\n </template>\n\n <!-- Association mode -->\n <template v-if=\"isAssociation && rawQuiz\">\n <p class=\"quiz-hint\">{{ t.associationHint }}</p>\n <div class=\"quiz-association\">\n <template v-for=\"(pair, i) in rawQuiz.pairs\" :key=\"i\">\n <label class=\"quiz-assoc-label\" :for=\"`quiz-assoc-${myId}-${i}`\">\n <template v-for=\"(part, pi) in parseRichText(pair.left)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </label>\n <div class=\"quiz-assoc-cell\">\n <select\n :id=\"`quiz-assoc-${myId}-${i}`\"\n :class=\"rowClass(i)\"\n :value=\"chosen[i] === null || chosen[i] === undefined ? '' : String(chosen[i])\"\n :disabled=\"validated\"\n @change=\"onSelect(i, $event)\"\n >\n <option value=\"\">{{ t.associationPlaceholder }}</option>\n <option v-for=\"oi in optionOrder\" :key=\"oi\" :value=\"String(oi)\">\n {{ rawQuiz.options[oi] }}\n </option>\n </select>\n <p v-if=\"validated && !rowCorrect(i)\" class=\"quiz-expected\">\n {{ t.expectedAnswer }} <code>{{ pair.right }}</code>\n </p>\n </div>\n </template>\n </div>\n </template>\n\n <!-- Fill-in-the-blank mode -->\n <template v-if=\"isInputMode && !isAssociation\">\n <p class=\"quiz-hint\">{{ t.inputHint }}</p>\n <div class=\"quiz-input-wrapper\">\n <input\n v-model=\"inputValue\"\n :class=\"inputClass\"\n type=\"text\"\n :disabled=\"validated\"\n :placeholder=\"t.inputPlaceholder\"\n :aria-label=\"quiz.question\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @keydown.enter.prevent\n />\n <p v-if=\"validated && !isCorrect\" class=\"quiz-expected\">\n {{ t.expectedAnswer }} <code>{{ rawQuiz?.expected[0] }}</code>\n </p>\n </div>\n </template>\n\n <!-- Explanation (rich text: supports **bold** and `code`) -->\n <div v-if=\"validated && quiz.explanation\" class=\"quiz-explanation\" role=\"note\">\n <strong>{{ t.explanation }}</strong>\n <template v-for=\"(part, pi) in parseRichText(quiz.explanation)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </div>\n </fieldset>\n</template>\n","<script setup lang=\"ts\">\nimport { ref, computed, provide, inject } from \"vue\"\nimport type { QuizLocale, QuizState, SavedAnswer } from \"./types/quiz\"\n\nconst t = inject<QuizLocale>(\"quiz-locale\")!\nconst questions = ref<QuizState[]>([])\nconst validated = ref(false)\n\n// Generate a storage key from the page path — set eagerly so children can read on mount\n// (Vue mounts children before parent, so onMounted would be too late)\nconst storageKey = typeof window !== 'undefined'\n ? 'quiz-state:' + window.location.pathname\n : ''\n\n// Restore quiz-level state immediately so validated is set before children mount\nrestoreState()\n\n// Question index counter for stable per-question storage keys\nlet questionIdx = 0\n\nprovide(\"quiz-validated\", validated)\nprovide(\"quiz-register\", (q: QuizState) => {\n questions.value.push(q)\n // returned disposer keeps counts correct on unmount (HMR, v-if)\n return () => {\n const i = questions.value.indexOf(q)\n if (i >= 0) questions.value.splice(i, 1)\n }\n})\n\n// Per-question persistence: each question gets a unique sub-key\nprovide(\"quiz-question-id\", () => questionIdx++)\nprovide(\"quiz-save-answer\", (qId: number, data: SavedAnswer) => {\n if (!storageKey) return\n try {\n sessionStorage.setItem(storageKey + \":q\" + qId, JSON.stringify(data))\n } catch { /* ignore */ }\n})\nprovide(\"quiz-get-answer\", (qId: number): SavedAnswer | null => {\n if (!storageKey) return null\n try {\n const raw = sessionStorage.getItem(storageKey + \":q\" + qId)\n return raw ? JSON.parse(raw) : null\n } catch { return null }\n})\n\n// Provide a reset trigger for child components\nconst resetCounter = ref(0)\nprovide(\"quiz-reset\", resetCounter)\n\nconst totalQuestions = computed(() => questions.value.length)\nconst answeredCount = computed(() =>\n questions.value.filter((q) => q.answered).length\n)\nconst correctCount = computed(() =>\n questions.value.filter((q) => q.isCorrect).length\n)\nconst allAnswered = computed(\n () => totalQuestions.value > 0 && answeredCount.value === totalQuestions.value,\n)\nconst progressPct = computed(() =>\n totalQuestions.value ? Math.round((answeredCount.value / totalQuestions.value) * 100) : 0\n)\n\nfunction validate() {\n validated.value = true\n saveState()\n}\n\nfunction reset() {\n validated.value = false\n resetCounter.value++\n clearState()\n}\n\n/* ── sessionStorage persistence ───────────────────────────────────── */\nfunction saveState() {\n if (!storageKey) return\n try {\n const data = { validated: validated.value, ts: Date.now() }\n sessionStorage.setItem(storageKey, JSON.stringify(data))\n } catch { /* storage full or unavailable */ }\n}\n\nfunction restoreState() {\n if (!storageKey) return\n try {\n const raw = sessionStorage.getItem(storageKey)\n if (!raw) return\n const data = JSON.parse(raw)\n if (data && data.validated) {\n validated.value = true\n }\n } catch { /* corrupted – ignore */ }\n}\n\nfunction clearState() {\n if (!storageKey) return\n try {\n const keysToRemove: string[] = []\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i)\n if (key && key.startsWith(storageKey)) {\n keysToRemove.push(key)\n }\n }\n keysToRemove.forEach((k) => sessionStorage.removeItem(k))\n } catch { /* ignore */ }\n}\n</script>\n\n<template>\n <div class=\"quiz-page\" role=\"region\" aria-label=\"Quiz\">\n <div\nclass=\"quiz-progress-bar\" role=\"progressbar\"\n :aria-valuenow=\"answeredCount\"\n :aria-valuemin=\"0\"\n :aria-valuemax=\"totalQuestions\"\n :aria-label=\"answeredCount + ' / ' + totalQuestions + ' ' + t.answered\"\n >\n <div class=\"quiz-progress-track\">\n <div\n class=\"quiz-progress-fill\"\n :style=\"{ width: progressPct + '%' }\"\n :class=\"{ complete: progressPct === 100 }\"\n ></div>\n </div>\n <span class=\"quiz-progress-label\" aria-live=\"polite\">\n {{ answeredCount }} / {{ totalQuestions }} {{ t.answered }}\n </span>\n </div>\n\n <slot />\n\n <div class=\"quiz-actions\">\n <button\n v-if=\"!validated\"\n class=\"quiz-btn quiz-btn-validate\"\n :disabled=\"!allAnswered\"\n @click=\"validate\"\n >\n {{ t.validate }}\n </button>\n\n <template v-if=\"validated\">\n <div\nclass=\"quiz-score\" role=\"status\" aria-live=\"polite\"\n :aria-label=\"correctCount + ' / ' + totalQuestions + ' ' + t.correctAnswers(correctCount)\"\n >\n <span class=\"quiz-score-value\">{{ correctCount }} / {{ totalQuestions }}</span>\n <span class=\"quiz-score-label\">\n {{ t.correctAnswers(correctCount) }}\n ({{ totalQuestions ? Math.round((correctCount / totalQuestions) * 100) : 0 }}%)\n </span>\n </div>\n <button class=\"quiz-btn quiz-btn-reset\" @click=\"reset\">\n {{ t.reset }}\n </button>\n </template>\n </div>\n </div>\n</template>\n","import type { App } from \"vue\"\nimport { ensureStylesInjected } from \"./styleManager\"\n\nexport { quizMarkdownPlugin } from \"./md-plugin\"\nexport { getLocale, locales } from \"./locales\"\nexport type { QuizData, QuizAnswer, QuizLocale, QuizState, SavedAnswer } from \"./types/quiz\"\n\nimport QuizQuestion from \"./QuizQuestion.vue\"\nimport QuizPage from \"./QuizPage.vue\"\nimport { getLocale as _getLocale } from \"./locales\"\n\nexport { QuizQuestion, QuizPage }\n\n/**\n * Register quiz components and locale in a VitePress `enhanceApp` hook.\n *\n * @example\n * // .vitepress/theme/index.ts\n * import { enhanceAppWithQuiz } from '@matinfo/vitepress-plugin-quiz'\n * export default {\n * enhanceApp({ app }) {\n * enhanceAppWithQuiz(app) // English (default)\n * enhanceAppWithQuiz(app, 'fr') // French\n * }\n * }\n */\nexport function enhanceAppWithQuiz(app: App, lang = \"en\"): void {\n ensureStylesInjected()\n app.provide(\"quiz-locale\", _getLocale(lang))\n app.component(\"QuizQuestion\", QuizQuestion)\n app.component(\"QuizPage\", QuizPage)\n}\n"],"names":["stylesInjected","ensureStylesInjected","styleId","style","quizCssInline","QUIZ_RE","CLOSE_RE","KEY_RE","KNOWN_KEYS","quizMarkdownPlugin","md","escapeHtml","state","startLine","endLine","silent","quizBlockRule","tokens","idx","t","open","close","startPos","startMax","lineText","nextLine","found","pos","max","line","innerLines","i","data","parseQuizBlock","a","token","renderQuizComponent","lines","question","answers","explanation","expected","pairs","distractors","shuffle","append","raw","m","key","value","join","cur","extra","x","entry","sep","sepLen","options","p","json","locales","n","getLocale","lang","parseRichText","text","parts","re","last","normalizeInput","props","__props","rawQuiz","computed","shuffleArray","arr","j","shuffledAnswers","ref","initAnswers","indexed","quiz","isInputMode","isAssociation","correctCount","isMultiple","selected","chosen","optionOrder","initAssociation","q","order","_","inputValue","register","inject","validated","resetCounter","getQuestionId","saveAnswer","getAnswer","myId","answered","c","isCorrect","input","rowCorrect","correctIndices","unregister","onUnmounted","watch","onMounted","saved","v","onSelect","row","event","next","persistState","toggle","orig","answerClass","answer","wasPicked","rowClass","inputClass","_createElementBlock","_normalizeClass","_unref","_createElementVNode","_hoisted_2","_Fragment","_renderList","part","pi","_hoisted_3","_toDisplayString","_hoisted_4","_hoisted_5","_createTextVNode","_openBlock","_hoisted_6","$event","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","pair","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_26","oi","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","questions","storageKey","restoreState","questionIdx","provide","qId","totalQuestions","answeredCount","allAnswered","progressPct","validate","saveState","reset","clearState","keysToRemove","_hoisted_1","_renderSlot","_ctx","_hoisted_8","enhanceAppWithQuiz","app","_getLocale","QuizQuestion","QuizPage"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
`,
|
|
3
|
-
`,
|
|
4
|
-
`}const S={en:{answered:"answered",validate:"Validate",reset:"Restart",correctAnswers:t=>`correct answer${t!==1?"s":""}`,multipleHint:"Multiple answers possible",explanation:"Explanation: ",inputHint:"Type your answer",inputPlaceholder:"Your answer…",expectedAnswer:"Expected answer:"},fr:{answered:"répondue(s)",validate:"Valider",reset:"Recommencer",correctAnswers:t=>`réponse${t>1?"s":""} correcte${t>1?"s":""}`,multipleHint:"Plusieurs réponses possibles",explanation:"Explication : ",inputHint:"Saisissez votre réponse",inputPlaceholder:"Votre réponse…",expectedAnswer:"Réponse attendue :"},de:{answered:"beantwortet",validate:"Überprüfen",reset:"Neu starten",correctAnswers:t=>`richtige Antwort${t!==1?"en":""}`,multipleHint:"Mehrere Antworten möglich",explanation:"Erklärung:",inputHint:"Geben Sie Ihre Antwort ein",inputPlaceholder:"Ihre Antwort…",expectedAnswer:"Erwartete Antwort:"},it:{answered:"risposta/e",validate:"Verifica",reset:"Ricominciare",correctAnswers:t=>`rispost${t!==1?"e corrette":"a corretta"}`,multipleHint:"Più risposte possibili",explanation:"Spiegazione: ",inputHint:"Digita la tua risposta",inputPlaceholder:"La tua risposta…",expectedAnswer:"Risposta attesa:"},es:{answered:"respondida(s)",validate:"Validar",reset:"Reiniciar",correctAnswers:t=>`respuesta${t!==1?"s correctas":" correcta"}`,multipleHint:"Varias respuestas posibles",explanation:"Explicación: ",inputHint:"Escribe tu respuesta",inputPlaceholder:"Tu respuesta…",expectedAnswer:"Respuesta esperada:"}};function D(t="en"){return S[t]??S.en}function V(t){const n=[],r=/(\*\*(.+?)\*\*)|(\*(.+?)\*)|(`([^`]+)`)/g;let l=0,o;for(;(o=r.exec(t))!==null;)o.index>l&&n.push({type:"text",value:t.slice(l,o.index)}),o[2]?n.push({type:"bold",value:o[2]}):o[4]?n.push({type:"italic",value:o[4]}):o[6]&&n.push({type:"code",value:o[6]}),l=r.lastIndex;return l<t.length&&n.push({type:"text",value:t.slice(l)}),n}const L=["aria-label"],O={class:"quiz-question-title"},K={key:0},J={key:1},U={key:2},G={key:0,class:"quiz-hint"},Y=["aria-multiselectable"],Z=["onClick","aria-selected","onKeydown"],X={class:"quiz-indicator","aria-hidden":"true"},ee={key:0,class:"quiz-check"},te={key:1,class:"quiz-empty"},ne={key:0,class:"quiz-check"},re={key:1,class:"quiz-empty"},oe={class:"quiz-answer-text"},ae={key:0},ie={key:1},se={key:2},le={class:"quiz-hint"},ce={class:"quiz-input-wrapper"},pe=["disabled","placeholder","aria-label"],de={key:0,class:"quiz-expected"},ue={key:2,class:"quiz-explanation",role:"note"},fe={key:0},ge={key:1},me={key:2},Q=e.defineComponent({__name:"QuizQuestion",props:{dataQuiz:{type:String,required:!0}},setup(t){const n=t,r=e.computed(()=>{try{return JSON.parse(n.dataQuiz)}catch{return null}});function l(c){const s=[...c];for(let a=s.length-1;a>0;a--){const z=Math.floor(Math.random()*(a+1));[s[a],s[z]]=[s[z],s[a]]}return s}const o=e.ref([]);function h(){if(!r.value||r.value.type==="input"){o.value=[];return}const c=r.value.answers.map((s,a)=>({...s,originalIndex:a}));o.value=r.value.shuffle?l(c):c}const d=e.computed(()=>r.value?{...r.value,answers:o.value}:null),i=e.computed(()=>r.value?.type==="input"),m=e.computed(()=>d.value&&!i.value?d.value.answers.filter(c=>c.correct).length:0),b=e.computed(()=>m.value>1),u=e.ref(new Set),k=e.ref(""),_=e.inject("quiz-register",null),f=e.inject("quiz-validated",e.ref(!1)),v=e.inject("quiz-reset",e.ref(0)),x=e.inject("quiz-locale"),B=e.inject("quiz-question-id",null),p=e.inject("quiz-save-answer",null),g=e.inject("quiz-get-answer",null),q=B?B():null,$=e.computed(()=>i.value?k.value.trim().length>0:u.value.size>0),N=e.computed(()=>{if(!d.value||!$.value)return!1;if(i.value){const s=k.value.trim().toLowerCase();return r.value.expected.some(a=>s===a.trim().toLowerCase())}const c=new Set(d.value.answers.map((s,a)=>s.correct?a:-1).filter(s=>s>=0));if(u.value.size!==c.size)return!1;for(const s of u.value)if(!c.has(s))return!1;return!0});_&&_({answered:$,isCorrect:N}),e.watch(v,()=>{u.value=new Set,k.value="",h()}),e.onMounted(()=>{if(h(),g&&q!==null){const c=g(q);c&&(c.type==="input"?k.value=c.input:c.type==="choice"&&(u.value=new Set(c.selected)))}});function C(c){if(f.value)return;const s=new Set(u.value);b.value?s.has(c)?s.delete(c):s.add(c):(s.clear(),s.add(c)),u.value=s,M()}e.watch(k,()=>{f.value||M()});function M(){!p||q===null||(i.value?p(q,{type:"input",input:k.value}):p(q,{type:"choice",selected:[...u.value]}))}function Be(c){if(!f.value)return u.value.has(c)?"quiz-answer selected":"quiz-answer";const s=d.value.answers[c],a=u.value.has(c);return s.correct&&a?"quiz-answer correct":s.correct&&!a?"quiz-answer missed":!s.correct&&a?"quiz-answer wrong":"quiz-answer"}const Ee=e.computed(()=>f.value?N.value?"quiz-input correct":"quiz-input wrong":"quiz-input");return(c,s)=>d.value?(e.openBlock(),e.createElementBlock("fieldset",{key:0,class:e.normalizeClass(["quiz-question",{validated:e.unref(f)}]),"aria-label":d.value.question},[e.createElementVNode("legend",O,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(V)(d.value.question),(a,z)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:z},[a.type==="bold"?(e.openBlock(),e.createElementBlock("strong",K,e.toDisplayString(a.value),1)):a.type==="italic"?(e.openBlock(),e.createElementBlock("em",J,e.toDisplayString(a.value),1)):a.type==="code"?(e.openBlock(),e.createElementBlock("code",U,e.toDisplayString(a.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(a.value),1)],64))],64))),128))]),i.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[b.value?(e.openBlock(),e.createElementBlock("p",G,e.toDisplayString(e.unref(x).multipleHint),1)):e.createCommentVNode("",!0),e.createElementVNode("ul",{class:"quiz-answers",role:"listbox","aria-multiselectable":b.value},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(d.value.answers,(a,z)=>(e.openBlock(),e.createElementBlock("li",{key:a.originalIndex,class:e.normalizeClass(Be(z)),onClick:y=>C(z),role:"option","aria-selected":u.value.has(z),tabindex:"0",onKeydown:[e.withKeys(y=>C(z),["enter"]),e.withKeys(e.withModifiers(y=>C(z),["prevent"]),["space"])]},[e.createElementVNode("span",X,[b.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[u.value.has(z)?(e.openBlock(),e.createElementBlock("span",ee,"✓")):(e.openBlock(),e.createElementBlock("span",te,"☐"))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[u.value.has(z)?(e.openBlock(),e.createElementBlock("span",ne,"●")):(e.openBlock(),e.createElementBlock("span",re,"○"))],64))]),e.createElementVNode("span",oe,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(V)(a.text),(y,Se)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:Se},[y.type==="bold"?(e.openBlock(),e.createElementBlock("strong",ae,e.toDisplayString(y.value),1)):y.type==="italic"?(e.openBlock(),e.createElementBlock("em",ie,e.toDisplayString(y.value),1)):y.type==="code"?(e.openBlock(),e.createElementBlock("code",se,e.toDisplayString(y.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(y.value),1)],64))],64))),128))])],42,Z))),128))],8,Y)],64)),i.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("p",le,e.toDisplayString(e.unref(x).inputHint),1),e.createElementVNode("div",ce,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":s[0]||(s[0]=a=>k.value=a),class:e.normalizeClass(Ee.value),type:"text",disabled:e.unref(f),placeholder:e.unref(x).inputPlaceholder,"aria-label":d.value.question,autocomplete:"off",spellcheck:"false",onKeydown:s[1]||(s[1]=e.withKeys(e.withModifiers(()=>{},["prevent"]),["enter"]))},null,42,pe),[[e.vModelText,k.value]]),e.unref(f)&&!N.value?(e.openBlock(),e.createElementBlock("p",de,[e.createTextVNode(e.toDisplayString(e.unref(x).expectedAnswer)+" ",1),e.createElementVNode("code",null,e.toDisplayString(r.value?.expected[0]),1)])):e.createCommentVNode("",!0)])],64)):e.createCommentVNode("",!0),e.unref(f)&&d.value.explanation?(e.openBlock(),e.createElementBlock("div",ue,[e.createElementVNode("strong",null,e.toDisplayString(e.unref(x).explanation),1),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(V)(d.value.explanation),(a,z)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:z},[a.type==="bold"?(e.openBlock(),e.createElementBlock("strong",fe,e.toDisplayString(a.value),1)):a.type==="italic"?(e.openBlock(),e.createElementBlock("em",ge,e.toDisplayString(a.value),1)):a.type==="code"?(e.openBlock(),e.createElementBlock("code",me,e.toDisplayString(a.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(a.value),1)],64))],64))),128))])):e.createCommentVNode("",!0)],10,L)):e.createCommentVNode("",!0)}}),he={class:"quiz-page",role:"region","aria-label":"Quiz"},ke=["aria-valuenow","aria-valuemax","aria-label"],ze={class:"quiz-progress-track"},be={class:"quiz-progress-label","aria-live":"polite"},we={class:"quiz-actions"},xe=["disabled"],ye=["aria-label"],qe={class:"quiz-score-value"},_e={class:"quiz-score-label"},A=e.defineComponent({__name:"QuizPage",setup(t){const n=e.inject("quiz-locale"),r=e.ref([]),l=e.ref(!1),o=typeof window<"u"?"quiz-state:"+window.location.pathname:"";x();let h=0;e.provide("quiz-validated",l),e.provide("quiz-register",p=>{r.value.push(p)}),e.provide("quiz-question-id",()=>h++),e.provide("quiz-save-answer",(p,g)=>{if(o)try{sessionStorage.setItem(o+":q"+p,JSON.stringify(g))}catch{}}),e.provide("quiz-get-answer",p=>{if(!o)return null;try{const g=sessionStorage.getItem(o+":q"+p);return g?JSON.parse(g):null}catch{return null}});const d=e.ref(0);e.provide("quiz-reset",d);const i=e.computed(()=>r.value.length),m=e.computed(()=>r.value.filter(p=>p.answered).length),b=e.computed(()=>r.value.filter(p=>p.isCorrect).length),u=e.computed(()=>m.value===i.value),k=e.computed(()=>i.value?Math.round(m.value/i.value*100):0);function _(){l.value=!0,v()}function f(){l.value=!1,d.value++,B()}function v(){if(o)try{const p={validated:l.value,ts:Date.now()};sessionStorage.setItem(o,JSON.stringify(p))}catch{}}function x(){if(o)try{const p=sessionStorage.getItem(o);if(!p)return;const g=JSON.parse(p);g&&g.validated&&(l.value=!0)}catch{}}function B(){if(o)try{const p=[];for(let g=0;g<sessionStorage.length;g++){const q=sessionStorage.key(g);q&&q.startsWith(o)&&p.push(q)}p.forEach(g=>sessionStorage.removeItem(g))}catch{}}return(p,g)=>(e.openBlock(),e.createElementBlock("div",he,[e.createElementVNode("div",{class:"quiz-progress-bar",role:"progressbar","aria-valuenow":m.value,"aria-valuemin":0,"aria-valuemax":i.value,"aria-label":m.value+" / "+i.value+" "+e.unref(n).answered},[e.createElementVNode("div",ze,[e.createElementVNode("div",{class:e.normalizeClass(["quiz-progress-fill",{complete:k.value===100}]),style:e.normalizeStyle({width:k.value+"%"})},null,6)]),e.createElementVNode("span",be,e.toDisplayString(m.value)+" / "+e.toDisplayString(i.value)+" "+e.toDisplayString(e.unref(n).answered),1)],8,ke),e.renderSlot(p.$slots,"default"),e.createElementVNode("div",we,[l.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:0,class:"quiz-btn quiz-btn-validate",disabled:!u.value,onClick:_},e.toDisplayString(e.unref(n).validate),9,xe)),l.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("div",{class:"quiz-score",role:"status","aria-live":"polite","aria-label":b.value+" / "+i.value+" "+e.unref(n).correctAnswers(b.value)},[e.createElementVNode("span",qe,e.toDisplayString(b.value)+" / "+e.toDisplayString(i.value),1),e.createElementVNode("span",_e,e.toDisplayString(e.unref(n).correctAnswers(b.value))+" ("+e.toDisplayString(i.value?Math.round(b.value/i.value*100):0)+"%) ",1)],8,ye),e.createElementVNode("button",{class:"quiz-btn quiz-btn-reset",onClick:f},e.toDisplayString(e.unref(n).reset),1)],64)):e.createCommentVNode("",!0)])]))}});function ve(t,n="en"){P(),t.provide("quiz-locale",D(n)),t.component("QuizQuestion",Q),t.component("QuizPage",A)}w.QuizPage=A,w.QuizQuestion=Q,w.enhanceAppWithQuiz=ve,w.getLocale=D,w.locales=S,w.quizMarkdownPlugin=T,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(q,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(q=typeof globalThis<"u"?globalThis:q||self,e(q.VitepressPluginQuiz={},q.Vue))})(this,(function(q,e){"use strict";const O=".quiz-progress-bar{position:sticky;top:var(--vp-nav-height, 64px);z-index:20;display:flex;align-items:center;gap:12px;margin:-20px -24px 24px;padding:12px 24px;background:var(--vp-c-bg);border-bottom:1px solid var(--vp-c-divider)}@media(max-width:959px){.quiz-progress-bar{top:calc(var(--vp-nav-height, 64px) - 16px)}}.quiz-progress-track{flex:1;height:8px;background:var(--vp-c-bg-soft);border-radius:4px;overflow:hidden}.quiz-progress-fill{height:100%;background:var(--vp-c-brand-1);border-radius:4px;transition:width .35s ease}.quiz-progress-fill.complete{background:var(--vp-c-green-1, #10b981)}.quiz-progress-label{font-size:13px;color:var(--vp-c-text-2);white-space:nowrap}.quiz-question{border:1px solid var(--vp-c-divider);border-radius:8px;padding:20px 24px;margin-bottom:16px;background:var(--vp-c-bg);transition:border-color .2s}.quiz-question-title{font-weight:600;font-size:15px;margin:0 0 6px;padding:0 5px;color:var(--vp-c-text-1);float:none;width:auto}.quiz-hint{font-size:13px;color:var(--vp-c-text-3);margin:0 0 10px;font-style:italic}.quiz-answers{list-style:none;padding:0;margin:0}.quiz-answer{display:flex;align-items:baseline;gap:10px;padding:8px 12px;margin:4px 0;border:1px solid transparent;border-radius:6px;cursor:pointer;transition:background-color .15s,border-color .15s;user-select:none;font-size:14px;color:var(--vp-c-text-1)}.quiz-answer:hover:not(.correct):not(.wrong):not(.missed){background:var(--vp-c-bg-soft)}.quiz-answer.selected{border-color:var(--vp-c-brand-1);background:var(--vp-c-brand-soft)}.quiz-answer.correct{border-color:var(--vp-c-green-1, #10b981);background:var(--vp-c-green-soft, rgba(16, 185, 129, .12));cursor:default}.quiz-answer.wrong{border-color:var(--vp-c-red-1, #ef4444);background:var(--vp-c-red-soft, rgba(239, 68, 68, .12));cursor:default}.quiz-answer.missed{border-color:var(--vp-c-yellow-1, #f59e0b);background:var(--vp-c-yellow-soft, rgba(245, 158, 11, .1));cursor:default}.validated .quiz-answer{pointer-events:none}.quiz-indicator{flex-shrink:0;width:18px;text-align:center;font-size:15px;line-height:1}.quiz-empty{color:var(--vp-c-text-3)}.quiz-check{color:var(--vp-c-brand-1)}.quiz-answer.correct .quiz-check{color:var(--vp-c-green-1, #10b981)}.quiz-answer.wrong .quiz-check{color:var(--vp-c-red-1, #ef4444)}.quiz-answer-text code{font-family:var(--vp-font-family-mono);font-size:13px;padding:1px 5px;border-radius:4px;background:var(--vp-c-bg-soft);color:var(--vp-c-text-1)}.quiz-explanation{margin-top:12px;padding:10px 14px;border-left:3px solid var(--vp-c-brand-1);background:var(--vp-c-bg-soft);border-radius:0 6px 6px 0;font-size:13px;color:var(--vp-c-text-2)}.quiz-actions{display:flex;flex-wrap:wrap;align-items:center;gap:16px;margin-top:24px;padding-top:20px;border-top:1px solid var(--vp-c-divider)}.quiz-btn{display:inline-flex;align-items:center;justify-content:center;padding:10px 28px;font-size:14px;font-weight:600;border:1px solid transparent;border-radius:8px;cursor:pointer;transition:opacity .2s,background .2s}.quiz-btn:disabled{opacity:.45;cursor:not-allowed}.quiz-btn-validate{background:var(--vp-c-brand-1);color:var(--vp-c-white, #fff)}.quiz-btn-validate:hover:not(:disabled){opacity:.88}.quiz-btn-reset{background:var(--vp-c-bg-soft);border-color:var(--vp-c-divider);color:var(--vp-c-text-1)}.quiz-btn-reset:hover{background:var(--vp-c-bg-mute)}.quiz-score{display:flex;align-items:baseline;gap:8px}.quiz-score-value{font-size:22px;font-weight:700;color:var(--vp-c-brand-1)}.quiz-score-label{font-size:14px;color:var(--vp-c-text-2)}.quiz-input-wrapper{margin-top:8px}.quiz-input{width:100%;max-width:400px;padding:8px 12px;font-size:14px;font-family:var(--vp-font-family-mono);border:1px solid var(--vp-c-divider);border-radius:6px;background:var(--vp-c-bg);color:var(--vp-c-text-1);outline:none;transition:border-color .15s}.quiz-input:focus{border-color:var(--vp-c-brand-1)}.quiz-input:disabled{cursor:not-allowed;opacity:.8}.quiz-input.correct{border-color:var(--vp-c-green-1, #10b981);background:var(--vp-c-green-soft, rgba(16, 185, 129, .12))}.quiz-input.wrong{border-color:var(--vp-c-red-1, #ef4444);background:var(--vp-c-red-soft, rgba(239, 68, 68, .12))}.quiz-expected{margin-top:6px;font-size:13px;color:var(--vp-c-text-2)}.quiz-expected code{font-family:var(--vp-font-family-mono);font-size:13px;padding:1px 5px;border-radius:4px;background:var(--vp-c-bg-soft);color:var(--vp-c-green-1, #10b981)}.quiz-association{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px 16px;align-items:start;margin-top:8px}.quiz-assoc-label{padding-top:8px;font-size:15px;color:var(--vp-c-text-1)}.quiz-assoc-select{width:100%;padding:8px 12px;font-size:14px;border:1px solid var(--vp-c-divider);border-radius:6px;background:var(--vp-c-bg);color:var(--vp-c-text-1);outline:none;transition:border-color .15s}.quiz-assoc-select:focus{border-color:var(--vp-c-brand-1)}.quiz-assoc-select:disabled{cursor:not-allowed;opacity:.8}.quiz-assoc-select.correct{border-color:var(--vp-c-green-1, #10b981);background:var(--vp-c-green-soft, rgba(16, 185, 129, .12))}.quiz-assoc-select.wrong{border-color:var(--vp-c-red-1, #ef4444);background:var(--vp-c-red-soft, rgba(239, 68, 68, .12))}@media(max-width:640px){.quiz-association{grid-template-columns:minmax(0,1fr);gap:4px}.quiz-assoc-label{padding-top:8px}.quiz-assoc-cell{margin-bottom:8px}}";let V=!1;function R(){if(typeof document>"u"||V)return;const n="vitepress-plugin-quiz-styles";if(document.getElementById(n)){V=!0;return}const i=document.createElement("style");i.id=n,i.textContent=O,document.head.appendChild(i),V=!0}const K=/^:::quiz\s*$/,L=/^:::\s*$/,J=/^([A-Za-z-]+):(.*)$/,W=new Set(["question","answer","answer-correct","answer-input","pair","distractor","explanation","explication","shuffle"]);function U(n){const i=n.utils.escapeHtml;n.block.ruler.before("fence","quiz",(o,d,l,z)=>Y(o,d,l,z,i),{alt:["paragraph","reference","blockquote","list"]}),n.renderer.rules.quiz=(o,d)=>o[d].content,n.core.ruler.push("quiz_page_wrap",o=>{if(!o.tokens.some(x=>x.type==="quiz"))return;const l=new o.Token("html_block","",0);l.content=`<QuizPage>
|
|
2
|
+
`,l.block=!0;const z=new o.Token("html_block","",0);z.content=`</QuizPage>
|
|
3
|
+
`,z.block=!0,o.tokens.unshift(l),o.tokens.push(z)})}function Y(n,i,o,d,l){if(n.sCount[i]-n.blkIndent>=4)return!1;const z=n.bMarks[i]+n.tShift[i],x=n.eMarks[i],g=n.src.slice(z,x);if(!K.test(g))return!1;if(d)return!0;let c=i+1,w=!1;for(;c<o;){const f=n.bMarks[c]+n.tShift[c],_=n.eMarks[c],u=n.src.slice(f,_);if(L.test(u)){w=!0;break}c++}if(!w)return!1;const y=[];for(let f=i+1;f<c;f++){const _=n.bMarks[f]+n.tShift[f],u=n.eMarks[f];y.push(n.src.slice(_,u))}const m=Z(y);if(m?.type==="choice"&&!m.answers.some(f=>f.correct)&&console.warn(`[vitepress-plugin-quiz] :quiz block at line ${i+1} has no 'answer-correct:'; it can never be answered correctly.`),!m)return console.warn(`[vitepress-plugin-quiz] Ignored invalid :::quiz block at line ${i+1}: needs a 'question:' and at least one 'answer:'/'answer-correct:', 'answer-input:', or two 'pair: A => B' lines.`),!1;const h=n.push("quiz","",0);return h.content=G(m,l),h.map=[i,c+1],h.block=!0,n.line=c+1,!0}function Z(n){let i="";const o=[];let d="";const l=[],z=[],x=[];let g=!1,c=null;for(const w of n){const y=w.trim();if(!y)continue;const m=J.exec(y),h=m?.[1].toLowerCase();if(!m||!h||!W.has(h)){c?.(y);continue}const f=m[2].trim(),_=(u,B)=>u?`${u} ${B}`:B;switch(h){case"question":i=f,c=u=>i=_(i,u);break;case"answer-correct":case"answer":{const u={text:f,correct:h==="answer-correct"};o.push(u),c=B=>u.text=_(u.text,B);break}case"answer-input":f&&l.push(f),c=null;break;case"pair":{let u=f.indexOf("=>"),B=2;if(u<0&&(u=f.indexOf("-->"),B=3),u<0){console.warn(`[vitepress-plugin-quiz] Ignored 'pair:' without '=>' or '-->': "${f}"`),c=null;break}const s={left:f.slice(0,u).trim(),right:f.slice(u+B).trim()};s.left&&s.right&&z.push(s),c=null;break}case"distractor":f&&x.push(f),c=null;break;case"explanation":case"explication":d=f,c=u=>d=_(d,u);break;case"shuffle":g=f.toLowerCase()==="true",c=null;break}}if(!i)return null;if(l.length>0)return{question:i,type:"input",answers:[],expected:l,pairs:[],options:[],explanation:d,shuffle:!1};if(z.length>=2){const w=[...new Set([...z.map(y=>y.right),...x])];return{question:i,type:"association",answers:[],expected:[],pairs:z,options:w,explanation:d,shuffle:g}}return o.length===0?null:{question:i,type:"choice",answers:o,expected:[],pairs:[],options:[],explanation:d,shuffle:g}}function G(n,i){const o=JSON.stringify(n);return`<QuizQuestion data-quiz="${i(o)}" />
|
|
4
|
+
`}const C={en:{answered:"answered",validate:"Validate",reset:"Restart",correctAnswers:n=>`correct answer${n!==1?"s":""}`,multipleHint:"Multiple answers possible",explanation:"Explanation: ",inputHint:"Type your answer",inputPlaceholder:"Your answer…",expectedAnswer:"Expected answer:",associationHint:"Match each item with its answer",associationPlaceholder:"Choose…"},fr:{answered:"répondue(s)",validate:"Valider",reset:"Recommencer",correctAnswers:n=>`réponse${n>1?"s":""} correcte${n>1?"s":""}`,multipleHint:"Plusieurs réponses possibles",explanation:"Explication : ",inputHint:"Saisissez votre réponse",inputPlaceholder:"Votre réponse…",expectedAnswer:"Réponse attendue :",associationHint:"Associez chaque élément à sa réponse",associationPlaceholder:"Choisir…"},de:{answered:"beantwortet",validate:"Überprüfen",reset:"Neu starten",correctAnswers:n=>`richtige Antwort${n!==1?"en":""}`,multipleHint:"Mehrere Antworten möglich",explanation:"Erklärung:",inputHint:"Geben Sie Ihre Antwort ein",inputPlaceholder:"Ihre Antwort…",expectedAnswer:"Erwartete Antwort:",associationHint:"Ordnen Sie jedem Element die passende Antwort zu",associationPlaceholder:"Auswählen…"},it:{answered:"risposta/e",validate:"Verifica",reset:"Ricominciare",correctAnswers:n=>`rispost${n!==1?"e corrette":"a corretta"}`,multipleHint:"Più risposte possibili",explanation:"Spiegazione: ",inputHint:"Digita la tua risposta",inputPlaceholder:"La tua risposta…",expectedAnswer:"Risposta attesa:",associationHint:"Abbina ogni elemento alla risposta corretta",associationPlaceholder:"Scegli…"},es:{answered:"respondida(s)",validate:"Validar",reset:"Reiniciar",correctAnswers:n=>`respuesta${n!==1?"s correctas":" correcta"}`,multipleHint:"Varias respuestas posibles",explanation:"Explicación: ",inputHint:"Escribe tu respuesta",inputPlaceholder:"Tu respuesta…",expectedAnswer:"Respuesta esperada:",associationHint:"Asocia cada elemento con su respuesta",associationPlaceholder:"Elegir…"}};function Q(n="en"){return C[n]??C.en}function S(n){const i=[],o=/(\*\*(?!\s)(.+?)\*\*)|(\*(?!\s)(.+?)(?<!\s)\*)|(`([^`]+)`)/g;let d=0,l;for(;(l=o.exec(n))!==null;)l.index>d&&i.push({type:"text",value:n.slice(d,l.index)}),l[2]?i.push({type:"bold",value:l[2]}):l[4]?i.push({type:"italic",value:l[4]}):l[6]&&i.push({type:"code",value:l[6]}),d=o.lastIndex;return d<n.length&&i.push({type:"text",value:n.slice(d)}),i}function P(n){return n.normalize("NFD").replace(/\p{M}/gu,"").trim().replace(/\s+/g," ").toLowerCase()}const X=["aria-label"],ee={class:"quiz-question-title"},te={key:0},ne={key:1},oe={key:2},re={key:0,class:"quiz-hint"},ae=["aria-multiselectable"],ie=["onClick","aria-selected","onKeydown"],se={class:"quiz-indicator","aria-hidden":"true"},le={key:0,class:"quiz-check"},ce={key:1,class:"quiz-empty"},pe={key:0,class:"quiz-check"},de={key:1,class:"quiz-empty"},ue={class:"quiz-answer-text"},fe={key:0},ge={key:1},me={key:2},he={class:"quiz-hint"},ke={class:"quiz-association"},xe=["for"],be={key:0},ze={key:1},ye={key:2},we={class:"quiz-assoc-cell"},qe=["id","value","disabled","onChange"],_e={value:""},Be=["value"],ve={key:0,class:"quiz-expected"},Ee={class:"quiz-hint"},Se={class:"quiz-input-wrapper"},Ne=["disabled","placeholder","aria-label"],Ve={key:0,class:"quiz-expected"},Ce={key:3,class:"quiz-explanation",role:"note"},Ae={key:0},De={key:1},Ie={key:2},M=e.defineComponent({__name:"QuizQuestion",props:{dataQuiz:{type:String,required:!0}},setup(n){const i=n,o=e.computed(()=>{try{return JSON.parse(i.dataQuiz)}catch{return null}});function d(r){const a=[...r];for(let t=a.length-1;t>0;t--){const p=Math.floor(Math.random()*(t+1));[a[t],a[p]]=[a[p],a[t]]}return a}const l=e.ref([]);function z(){if(!o.value||o.value.type!=="choice"){l.value=[];return}const r=o.value.answers.map((a,t)=>({...a,originalIndex:t}));l.value=o.value.shuffle?d(r):r}const x=e.computed(()=>o.value?{...o.value,answers:l.value}:null),g=e.computed(()=>o.value?.type==="input"),c=e.computed(()=>o.value?.type==="association"),w=e.computed(()=>x.value&&!g.value&&!c.value?x.value.answers.filter(r=>r.correct).length:0),y=e.computed(()=>w.value>1),m=e.ref(new Set),h=e.ref([]),f=e.ref([]);function _(){const r=o.value;if(!r||r.type!=="association"){h.value=[],f.value=[];return}h.value=r.pairs.map(()=>null);const a=r.options.map((t,p)=>p);f.value=r.shuffle?d(a):a}const u=e.ref(""),B=e.inject("quiz-register",null),s=e.inject("quiz-validated",e.ref(!1)),b=e.inject("quiz-reset",e.ref(0)),v=e.inject("quiz-locale"),H=e.inject("quiz-question-id",null),N=e.inject("quiz-save-answer",null),j=e.inject("quiz-get-answer",null),E=H?H():null,T=e.computed(()=>c.value?h.value.length>0&&h.value.every(r=>r!==null):g.value?u.value.trim().length>0:m.value.size>0),A=e.computed(()=>{if(!x.value||!T.value)return!1;if(g.value){const a=P(u.value);return o.value.expected.some(t=>a===P(t))}if(c.value)return o.value.pairs.every((a,t)=>D(t));const r=new Set(o.value.answers.map((a,t)=>a.correct?t:-1).filter(a=>a>=0));if(m.value.size!==r.size)return!1;for(const a of m.value)if(!r.has(a))return!1;return!0});function D(r){const a=o.value,t=h.value[r];return!a||t===null||t===void 0?!1:a.options[t]===a.pairs[r].right}if(B&&o.value){const r=B({answered:T,isCorrect:A});e.onUnmounted(r)}e.watch(b,()=>{m.value=new Set,u.value="",z(),_()}),e.onMounted(()=>{if(z(),_(),j&&E!==null){const r=j(E);if(r){if(r.type==="input"&&g.value&&typeof r.input=="string")u.value=r.input;else if(r.type==="association"&&c.value&&Array.isArray(r.chosen)){const a=o.value?.options.length??0;h.value=h.value.map((t,p)=>{const k=r.chosen[p];return typeof k=="number"&&Number.isInteger(k)&&k>=0&&k<a?k:null})}else if(r.type==="choice"&&!c.value&&!g.value&&Array.isArray(r.selected)){const a=o.value?.answers.length??0;m.value=new Set(r.selected.filter(t=>Number.isInteger(t)&&t>=0&&t<a))}}}});function Ke(r,a){if(s.value)return;const t=a.target.value,p=[...h.value];p[r]=t===""?null:Number(t),h.value=p,$()}function I(r){if(s.value)return;const a=new Set(m.value);y.value?a.has(r)?a.delete(r):a.add(r):(a.clear(),a.add(r)),m.value=a,$()}e.watch(u,()=>{s.value||$()});function $(){!N||E===null||(c.value?N(E,{type:"association",chosen:[...h.value]}):g.value?N(E,{type:"input",input:u.value}):N(E,{type:"choice",selected:[...m.value]}))}function Le(r){const a=m.value.has(r.originalIndex);return s.value?r.correct&&a?"quiz-answer correct":r.correct&&!a?"quiz-answer missed":!r.correct&&a?"quiz-answer wrong":"quiz-answer":a?"quiz-answer selected":"quiz-answer"}function Je(r){return s.value?D(r)?"quiz-assoc-select correct":"quiz-assoc-select wrong":"quiz-assoc-select"}const We=e.computed(()=>s.value?A.value?"quiz-input correct":"quiz-input wrong":"quiz-input");return(r,a)=>x.value?(e.openBlock(),e.createElementBlock("fieldset",{key:0,class:e.normalizeClass(["quiz-question",{validated:e.unref(s)}]),"aria-label":x.value.question},[e.createElementVNode("legend",ee,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(S)(x.value.question),(t,p)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:p},[t.type==="bold"?(e.openBlock(),e.createElementBlock("strong",te,e.toDisplayString(t.value),1)):t.type==="italic"?(e.openBlock(),e.createElementBlock("em",ne,e.toDisplayString(t.value),1)):t.type==="code"?(e.openBlock(),e.createElementBlock("code",oe,e.toDisplayString(t.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(t.value),1)],64))],64))),128))]),!g.value&&!c.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[y.value?(e.openBlock(),e.createElementBlock("p",re,e.toDisplayString(e.unref(v).multipleHint),1)):e.createCommentVNode("",!0),e.createElementVNode("ul",{class:"quiz-answers",role:"listbox","aria-multiselectable":y.value},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(x.value.answers,t=>(e.openBlock(),e.createElementBlock("li",{key:t.originalIndex,class:e.normalizeClass(Le(t)),onClick:p=>I(t.originalIndex),role:"option","aria-selected":m.value.has(t.originalIndex),tabindex:"0",onKeydown:[e.withKeys(p=>I(t.originalIndex),["enter"]),e.withKeys(e.withModifiers(p=>I(t.originalIndex),["prevent"]),["space"])]},[e.createElementVNode("span",se,[y.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[m.value.has(t.originalIndex)?(e.openBlock(),e.createElementBlock("span",le,"✓")):(e.openBlock(),e.createElementBlock("span",ce,"☐"))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[m.value.has(t.originalIndex)?(e.openBlock(),e.createElementBlock("span",pe,"●")):(e.openBlock(),e.createElementBlock("span",de,"○"))],64))]),e.createElementVNode("span",ue,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(S)(t.text),(p,k)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:k},[p.type==="bold"?(e.openBlock(),e.createElementBlock("strong",fe,e.toDisplayString(p.value),1)):p.type==="italic"?(e.openBlock(),e.createElementBlock("em",ge,e.toDisplayString(p.value),1)):p.type==="code"?(e.openBlock(),e.createElementBlock("code",me,e.toDisplayString(p.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(p.value),1)],64))],64))),128))])],42,ie))),128))],8,ae)],64)):e.createCommentVNode("",!0),c.value&&o.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("p",he,e.toDisplayString(e.unref(v).associationHint),1),e.createElementVNode("div",ke,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.value.pairs,(t,p)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:p},[e.createElementVNode("label",{class:"quiz-assoc-label",for:`quiz-assoc-${e.unref(E)}-${p}`},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(S)(t.left),(k,Ue)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:Ue},[k.type==="bold"?(e.openBlock(),e.createElementBlock("strong",be,e.toDisplayString(k.value),1)):k.type==="italic"?(e.openBlock(),e.createElementBlock("em",ze,e.toDisplayString(k.value),1)):k.type==="code"?(e.openBlock(),e.createElementBlock("code",ye,e.toDisplayString(k.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(k.value),1)],64))],64))),128))],8,xe),e.createElementVNode("div",we,[e.createElementVNode("select",{id:`quiz-assoc-${e.unref(E)}-${p}`,class:e.normalizeClass(Je(p)),value:h.value[p]===null||h.value[p]===void 0?"":String(h.value[p]),disabled:e.unref(s),onChange:k=>Ke(p,k)},[e.createElementVNode("option",_e,e.toDisplayString(e.unref(v).associationPlaceholder),1),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(f.value,k=>(e.openBlock(),e.createElementBlock("option",{key:k,value:String(k)},e.toDisplayString(o.value.options[k]),9,Be))),128))],42,qe),e.unref(s)&&!D(p)?(e.openBlock(),e.createElementBlock("p",ve,[e.createTextVNode(e.toDisplayString(e.unref(v).expectedAnswer)+" ",1),e.createElementVNode("code",null,e.toDisplayString(t.right),1)])):e.createCommentVNode("",!0)])],64))),128))])],64)):e.createCommentVNode("",!0),g.value&&!c.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:2},[e.createElementVNode("p",Ee,e.toDisplayString(e.unref(v).inputHint),1),e.createElementVNode("div",Se,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":a[0]||(a[0]=t=>u.value=t),class:e.normalizeClass(We.value),type:"text",disabled:e.unref(s),placeholder:e.unref(v).inputPlaceholder,"aria-label":x.value.question,autocomplete:"off",spellcheck:"false",onKeydown:a[1]||(a[1]=e.withKeys(e.withModifiers(()=>{},["prevent"]),["enter"]))},null,42,Ne),[[e.vModelText,u.value]]),e.unref(s)&&!A.value?(e.openBlock(),e.createElementBlock("p",Ve,[e.createTextVNode(e.toDisplayString(e.unref(v).expectedAnswer)+" ",1),e.createElementVNode("code",null,e.toDisplayString(o.value?.expected[0]),1)])):e.createCommentVNode("",!0)])],64)):e.createCommentVNode("",!0),e.unref(s)&&x.value.explanation?(e.openBlock(),e.createElementBlock("div",Ce,[e.createElementVNode("strong",null,e.toDisplayString(e.unref(v).explanation),1),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(S)(x.value.explanation),(t,p)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:p},[t.type==="bold"?(e.openBlock(),e.createElementBlock("strong",Ae,e.toDisplayString(t.value),1)):t.type==="italic"?(e.openBlock(),e.createElementBlock("em",De,e.toDisplayString(t.value),1)):t.type==="code"?(e.openBlock(),e.createElementBlock("code",Ie,e.toDisplayString(t.value),1)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode(e.toDisplayString(t.value),1)],64))],64))),128))])):e.createCommentVNode("",!0)],10,X)):e.createCommentVNode("",!0)}}),$e={class:"quiz-page",role:"region","aria-label":"Quiz"},Qe=["aria-valuenow","aria-valuemax","aria-label"],Pe={class:"quiz-progress-track"},Me={class:"quiz-progress-label","aria-live":"polite"},Fe={class:"quiz-actions"},He=["disabled"],je=["aria-label"],Te={class:"quiz-score-value"},Oe={class:"quiz-score-label"},F=e.defineComponent({__name:"QuizPage",setup(n){const i=e.inject("quiz-locale"),o=e.ref([]),d=e.ref(!1),l=typeof window<"u"?"quiz-state:"+window.location.pathname:"";u();let z=0;e.provide("quiz-validated",d),e.provide("quiz-register",s=>(o.value.push(s),()=>{const b=o.value.indexOf(s);b>=0&&o.value.splice(b,1)})),e.provide("quiz-question-id",()=>z++),e.provide("quiz-save-answer",(s,b)=>{if(l)try{sessionStorage.setItem(l+":q"+s,JSON.stringify(b))}catch{}}),e.provide("quiz-get-answer",s=>{if(!l)return null;try{const b=sessionStorage.getItem(l+":q"+s);return b?JSON.parse(b):null}catch{return null}});const x=e.ref(0);e.provide("quiz-reset",x);const g=e.computed(()=>o.value.length),c=e.computed(()=>o.value.filter(s=>s.answered).length),w=e.computed(()=>o.value.filter(s=>s.isCorrect).length),y=e.computed(()=>g.value>0&&c.value===g.value),m=e.computed(()=>g.value?Math.round(c.value/g.value*100):0);function h(){d.value=!0,_()}function f(){d.value=!1,x.value++,B()}function _(){if(l)try{const s={validated:d.value,ts:Date.now()};sessionStorage.setItem(l,JSON.stringify(s))}catch{}}function u(){if(l)try{const s=sessionStorage.getItem(l);if(!s)return;const b=JSON.parse(s);b&&b.validated&&(d.value=!0)}catch{}}function B(){if(l)try{const s=[];for(let b=0;b<sessionStorage.length;b++){const v=sessionStorage.key(b);v&&v.startsWith(l)&&s.push(v)}s.forEach(b=>sessionStorage.removeItem(b))}catch{}}return(s,b)=>(e.openBlock(),e.createElementBlock("div",$e,[e.createElementVNode("div",{class:"quiz-progress-bar",role:"progressbar","aria-valuenow":c.value,"aria-valuemin":0,"aria-valuemax":g.value,"aria-label":c.value+" / "+g.value+" "+e.unref(i).answered},[e.createElementVNode("div",Pe,[e.createElementVNode("div",{class:e.normalizeClass(["quiz-progress-fill",{complete:m.value===100}]),style:e.normalizeStyle({width:m.value+"%"})},null,6)]),e.createElementVNode("span",Me,e.toDisplayString(c.value)+" / "+e.toDisplayString(g.value)+" "+e.toDisplayString(e.unref(i).answered),1)],8,Qe),e.renderSlot(s.$slots,"default"),e.createElementVNode("div",Fe,[d.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:0,class:"quiz-btn quiz-btn-validate",disabled:!y.value,onClick:h},e.toDisplayString(e.unref(i).validate),9,He)),d.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("div",{class:"quiz-score",role:"status","aria-live":"polite","aria-label":w.value+" / "+g.value+" "+e.unref(i).correctAnswers(w.value)},[e.createElementVNode("span",Te,e.toDisplayString(w.value)+" / "+e.toDisplayString(g.value),1),e.createElementVNode("span",Oe,e.toDisplayString(e.unref(i).correctAnswers(w.value))+" ("+e.toDisplayString(g.value?Math.round(w.value/g.value*100):0)+"%) ",1)],8,je),e.createElementVNode("button",{class:"quiz-btn quiz-btn-reset",onClick:f},e.toDisplayString(e.unref(i).reset),1)],64)):e.createCommentVNode("",!0)])]))}});function Re(n,i="en"){R(),n.provide("quiz-locale",Q(i)),n.component("QuizQuestion",M),n.component("QuizPage",F)}q.QuizPage=F,q.QuizQuestion=M,q.enhanceAppWithQuiz=Re,q.getLocale=Q,q.locales=C,q.quizMarkdownPlugin=U,Object.defineProperty(q,Symbol.toStringTag,{value:"Module"})}));
|
|
5
5
|
//# sourceMappingURL=vitepress-plugin-quiz.umd.cjs.map
|