Files
2CInfo/assets/atelier-texte.js
2026-09-21 10:56:04 +02:00

97 lines
3.7 KiB
JavaScript

/* ==================================================================
Outils communs aux cours de traitement de texte (3e TQ, 4e TQ)
------------------------------------------------------------------
Trois briques réutilisables d'un module à l'autre :
quiz(element, questions) questionnaire à choix, correction immédiate
chasse(...) chasse aux fautes dans un texte
suivreSommaire() surligne l'entrée courante du sommaire
Chaque page de module charge ce fichier, puis déclare ses propres
données dans un <script> qui lui est propre.
================================================================== */
"use strict";
/* ---------- questionnaire à choix multiples ----------
questions : [{q: énoncé, r: [réponses], b: index de la bonne, e: explication}] */
function quiz(el, questions){
if (!el) return;
el.innerHTML = questions.map(function(q, i){
return '<div class="q" data-i="' + i + '"><p>' + (i + 1) + '. ' + q.q + '</p>' +
q.r.map(function(r, j){
return '<label><input type="radio" name="' + el.id + '-' + i + '" value="' + j + '">' + r + '</label>';
}).join('') +
'<div class="verdict" role="status" aria-live="polite"></div></div>';
}).join('');
el.addEventListener('change', function(e){
var bloc = e.target.closest('.q');
var i = +bloc.dataset.i, q = questions[i];
bloc.querySelectorAll('label').forEach(function(l, j){
l.className = (j === q.b) ? 'bon' : (l.querySelector('input').checked ? 'mauvais' : '');
});
bloc.querySelector('.verdict').textContent =
(+e.target.value === q.b ? 'Exact. ' : 'Non. ') + q.e;
});
}
/* ---------- chasse aux fautes ----------
jetons : [{t: mot, f: true si c'est une faute}] */
function chasse(conteneur, scoreEl, resetBtn, solBtn, jetons, total, motFinal){
if (!conteneur) return;
var trouves = new Set(), rates = new Set();
function maj(){
conteneur.querySelectorAll('span').forEach(function(s){
var i = +s.dataset.i;
s.className = trouves.has(i) ? 'trouve' : (rates.has(i) ? 'rate' : '');
});
scoreEl.textContent = trouves.size + ' sur ' + total + ' trouvées' +
(rates.size ? ', ' + rates.size + ' clic' + (rates.size > 1 ? 's' : '') + ' à côté' : '') +
(trouves.size === total ? '. ' + motFinal : '');
}
conteneur.innerHTML = jetons.map(function(j, i){
return '<span data-i="' + i + '">' + j.t + '</span>';
}).join(' ');
conteneur.addEventListener('click', function(e){
var s = e.target.closest('span');
if (!s) return;
var i = +s.dataset.i;
if (jetons[i].f) trouves.add(i); else rates.add(i);
maj();
});
resetBtn.addEventListener('click', function(){
trouves = new Set(); rates = new Set(); maj();
});
solBtn.addEventListener('click', function(){
jetons.forEach(function(j, i){ if (j.f) trouves.add(i); });
rates = new Set(); maj();
});
maj();
}
/* ---------- surlignage de l'entrée courante du sommaire ---------- */
function suivreSommaire(){
var liens = [].slice.call(document.querySelectorAll('.sommaire-lat a[href^="#"]'));
var cibles = liens
.map(function(a){ return document.getElementById(a.getAttribute('href').slice(1)); })
.filter(Boolean);
if (!cibles.length || !window.IntersectionObserver) return;
var obs = new IntersectionObserver(function(entrees){
entrees.forEach(function(en){
if (!en.isIntersecting) return;
liens.forEach(function(a){
a.classList.toggle('on', a.getAttribute('href') === '#' + en.target.id);
});
});
}, { rootMargin: '-10% 0px -80% 0px' });
cibles.forEach(function(c){ obs.observe(c); });
}
window.addEventListener('DOMContentLoaded', suivreSommaire);