Enrichit le reporting SCORM/xAPI et met en conformité RGAA le player
Build and deploy / test-python (push) Successful in 5m56s
Build and deploy / test-js (push) Successful in 51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

SCORM/xAPI :
- Ajoute l'export SCORM 2004 (3rd/4th edition) au choix, en plus du 1.2
  par défaut : sépare completion_status/success_status (un échec reste
  "completed" au lieu de retomber à tort en "incomplete" comme force la
  1.2), remonte aussi cmi.interactions.n.* par question répondue.
- Fournit cmi.core.score.min/max (1.2 et 2004), calculé depuis les
  récompenses de quiz du jeu, pour que le LMS affiche un vrai pourcentage
  au lieu du score brut à tort étiqueté "%".
- Libellés de verbes xAPI en français en plus de l'anglais.

Accessibilité (RGAA/WCAG 2.1 AA) sur le player :
- Navigation clavier des objets de scène "au clic"/"au survol"
  (tabindex, role, Entrée/Espace, focus/blur).
- alt sur les images (nom auteur ou décoratif), aria-hidden sur les
  icônes seules, role="dialog"/aria-live sur les boîtes de dialogue/quiz.
- Landmark <main> + titre de page, respect de prefers-reduced-motion.
- Le quiz n'avance plus automatiquement après un délai fixe : bouton
  "Continuer →" explicite (RGAA 2.2.1).
- Avertissement de contraste dans l'éditeur de style de dialogue.
- Déclaration d'accessibilité téléchargeable depuis la modale d'export.
This commit is contained in:
william
2026-09-06 00:17:51 +02:00
parent f7a50e5afe
commit c504ace167
36 changed files with 1581 additions and 79 deletions
+14 -2
View File
@@ -114,12 +114,17 @@ function forgeStyleString(el, parentFlexDirection, widgetKey) {
return baseStyle + (userStyle ? " " + userStyle + ";" : "");
}
// Port de attr_string.py.
// Port de attr_string.py. "alt" est le seul attribut dont la chaîne VIDE
// a un sens propre (RGAA/WCAG 1.1.1 : alt="" marque explicitement une
// image comme décorative, ce que "pas d'alt du tout" ne fait pas pour un
// lecteur d'écran) — tous les autres attributs vides sont omis comme
// avant (une valeur vide y équivaut à "non réglé").
function forgeAttrString(attrs, extraStyle) {
var parts = ['style="' + forgeHtmlEscape(extraStyle) + '"'];
Object.keys(attrs).forEach(function (k) {
var v = attrs[k];
if (v === null || v === undefined || v === "" || v === false) return;
if (v === null || v === undefined || v === false) return;
if (v === "" && k !== "alt") return;
parts.push(v === true ? forgeHtmlEscape(k) : forgeHtmlEscape(k) + '="' + forgeHtmlEscape(v) + '"');
});
return parts.join(" ");
@@ -275,6 +280,13 @@ function forgeRenderElementHtml(el, gameData, childrenMap, ctx, parentFlexDirect
var hoverText = attrsRaw._survol_texte;
if (hoverText) attrs["data-hover-text"] = forgeApplyCtx(hoverText, ctx);
// alt (RGAA/WCAG 1.1.1) : le widget "image" n'a pas de champ de
// description dédié dans l'éditeur — alt="" (décoratif) par défaut
// plutôt qu'aucun attribut du tout, jamais le nom de fichier brut par
// défaut du navigateur. Ne touche pas à un alt déjà posé (pass-through
// via forgeVisibleAttrs, si l'auteur en règle un un jour).
if (tag === "img" && !("alt" in attrs)) attrs.alt = "";
if (meta.selfClosing) {
return mark("<" + tag + " " + forgeAttrString(attrs, style) + ">");
}