2026-03-12 08:05:10 +00:00
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/hanzi-writer@3.5/dist/hanzi-writer.min.js"></script>
|
|
|
|
|
|
<script>
|
2026-03-15 16:28:39 +00:00
|
|
|
|
function createMyReusableModule() {
|
|
|
|
|
|
|
|
|
|
|
|
function init(options = {}) {
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
|
|
|
|
|
let iNb = 0;
|
2026-03-15 16:28:39 +00:00
|
|
|
|
let datas = options.datas;
|
|
|
|
|
|
let datas_length = datas.length;
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
displayChallenge(
|
|
|
|
|
|
options.challengeID,
|
|
|
|
|
|
datas[iNb].valeur,
|
|
|
|
|
|
datas[iNb].pinyin
|
|
|
|
|
|
);
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
// --- INITIALISATION MULTI‑CANVAS ---
|
|
|
|
|
|
let { writers, okArray } = initMultiCanvas(
|
|
|
|
|
|
options.canvasID,
|
|
|
|
|
|
datas[iNb].hanzi,
|
|
|
|
|
|
options.view_settings
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
startMultiQuiz(writers, okArray);
|
|
|
|
|
|
|
|
|
|
|
|
const bouton = document.querySelector("#" + options.button_OK_ID);
|
|
|
|
|
|
|
|
|
|
|
|
const handleClick = () => {
|
|
|
|
|
|
|
|
|
|
|
|
let isOK = checkAll(okArray, options.feedbackID);
|
|
|
|
|
|
|
|
|
|
|
|
switch (isOK) {
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
// incorrect → rien
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
// correct → mot suivant
|
|
|
|
|
|
iNb++;
|
|
|
|
|
|
|
|
|
|
|
|
if (iNb >= datas_length) {
|
|
|
|
|
|
document.getElementById(options.feedbackID).textContent = "Fini !";
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
displayChallenge(
|
|
|
|
|
|
options.challengeID,
|
|
|
|
|
|
datas[iNb].valeur,
|
|
|
|
|
|
datas[iNb].pinyin
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Réinitialiser les canvas pour le nouveau mot
|
|
|
|
|
|
let res = initMultiCanvas(
|
|
|
|
|
|
options.canvasID,
|
|
|
|
|
|
datas[iNb].hanzi,
|
|
|
|
|
|
options.view_settings
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
writers = res.writers;
|
|
|
|
|
|
okArray = res.okArray;
|
|
|
|
|
|
|
|
|
|
|
|
startMultiQuiz(writers, okArray);
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bouton.addEventListener("click", handleClick);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
// AFFICHAGE DU CHALLENGE
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
function displayChallenge(divName, chineseChar, pinyin) {
|
|
|
|
|
|
document.getElementById(divName).textContent =
|
|
|
|
|
|
"Écrire : " + chineseChar + " / " + pinyin;
|
|
|
|
|
|
}
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
// CRÉATION MULTI‑CANVAS
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
function initMultiCanvas(containerID, hanzi, view_settings) {
|
|
|
|
|
|
|
|
|
|
|
|
const chars = [...hanzi]; // "十一" → ["十","一"]
|
|
|
|
|
|
|
|
|
|
|
|
const container = document.getElementById(containerID);
|
|
|
|
|
|
container.innerHTML = ""; // reset
|
|
|
|
|
|
|
|
|
|
|
|
let writers = [];
|
|
|
|
|
|
let okArray = new Array(chars.length).fill(false);
|
|
|
|
|
|
|
|
|
|
|
|
chars.forEach((char, index) => {
|
|
|
|
|
|
|
|
|
|
|
|
const c = document.createElement("div");
|
|
|
|
|
|
c.id = `${containerID}_${index}`;
|
|
|
|
|
|
c.style.display = "inline-block";
|
|
|
|
|
|
c.style.marginRight = "10px";
|
|
|
|
|
|
container.appendChild(c);
|
|
|
|
|
|
|
|
|
|
|
|
const hw = HanziWriter.create(c.id, char, {
|
2026-03-12 08:05:10 +00:00
|
|
|
|
width: 150,
|
|
|
|
|
|
height: 150,
|
2026-03-15 16:28:39 +00:00
|
|
|
|
showCharacter: view_settings.showCharacter,
|
|
|
|
|
|
showOutline: view_settings.showOutline,
|
2026-03-12 08:05:10 +00:00
|
|
|
|
showHintAfterMisses: 1,
|
|
|
|
|
|
highlightOnComplete: false,
|
|
|
|
|
|
padding: 5
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
writers.push(hw);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return { writers, okArray };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
// LANCER UN QUIZ PAR CANVAS
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
function startMultiQuiz(writers, okArray) {
|
|
|
|
|
|
|
|
|
|
|
|
writers.forEach((hw, idx) => {
|
|
|
|
|
|
|
|
|
|
|
|
okArray[idx] = false; // reset
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
|
|
|
|
|
hw.quiz({
|
2026-03-15 16:28:39 +00:00
|
|
|
|
onMistake: () => { okArray[idx] = false; },
|
|
|
|
|
|
onCorrectStroke: () => {},
|
|
|
|
|
|
onComplete: () => { okArray[idx] = true; }
|
2026-03-12 08:05:10 +00:00
|
|
|
|
});
|
2026-03-15 16:28:39 +00:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
// CHECK GLOBAL
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
function checkAll(okArray, feedbackId) {
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
const allOK = okArray.every(v => v === true);
|
2026-03-12 08:05:10 +00:00
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
if (allOK) {
|
|
|
|
|
|
document.getElementById(feedbackId).textContent = "✔️ Bravo !";
|
|
|
|
|
|
document.getElementById(feedbackId).style.color = "green";
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
document.getElementById(feedbackId).textContent = "❌ Incorrect, continue !";
|
|
|
|
|
|
document.getElementById(feedbackId).style.color = "red";
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
2026-03-12 08:05:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-15 16:28:39 +00:00
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
// EXPORT
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
|
return {
|
|
|
|
|
|
init
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|