Update Concepts et objets de MACAO: ajout exercices Flash-only authored by Eliott Sammier's avatar Eliott Sammier
Cette page décrit la structure de Macao-Legacy et l'emplacement des données de contenu.
*À plusieurs reprises, on a besoin de décrire un motif de nommage : dans ces cas, le caractère `#` correspond à un chiffre, et `_` à n'importe quel caractère alphanumérique. Quand ces caractères sont répétés, ils décrivent par défaut un champ de longueur variable (exemple: `###` désigne de 1 à 3 chiffres)*
---
**Modules** : Macao est composé de 3 modules (Macao 1, 2 et 3). Macao 1 et 2 partagent la même base de code `macao_12`, Macao 3 a été développé plus tard et réside dans `macao_3`.
[[_TOC_]]
# Dans Macao 1 et 2 :
![Macao_12_concepts_annotation](uploads/3d911416917cd59c2e27ae0ca0c80309/Screenshot_2024-08-15_17-17-18.png)
![class_diagram.drawio.svg](uploads/a8e9b401c9a8d8b1927ee88b2b00f4b4/class_diagram.drawio.svg)
---
## Parties
Un module contient une ou plusieurs parties _(ex: "Reconnaître les syllabes")_, qui elles-mêmes peuvent contenir d'autres (sous-)parties. Côté code, une partie a la même représentation qu'un module, c'est un élément sans contenu propre, décrit seulement dans le manifeste [`imsmanifest.xml`](https://gitlab.tetras-libre.fr/macao/macao-legacy/-/blob/main/Basilisk/MACAO/macao_12/imsmanifest.xml)
<details>
<summary>Exemple XML</summary>
```xml
<organization>
<!-- ... -->
<item identifier="MosMod10"> <!-- module "MosMod10" -->
<title>MACAO 1 - S'entraîner à la reconnaissance</title> <!-- titre de MosMod10 -->
<!-- Contenu de MosMod10 -->
<item identifier="MosMod11">
<title>Reconnaître les syllabes</title>
<!-- Contenu de MosMod11 -->
<item identifier="MosEtp129" identifierref="rsrcMosEtp129">
<!-- Sous-partie "MosEtp129", contenu défini dans MosEtp129.html -->
<title>&gt; Reconnaître les syllabes en anglais oral</title>
</item>
</item>
<item identifier="MosMod34">
<title>Reconnaître les auxiliaires, les prépositions et les déterminants</title>
<item identifier="MosEtp210" identifierref="rsrcMosEtp210">
<title>&gt; Reconnaître les auxiliaires</title>
</item>
<item identifier="MosEtp335" identifierref="rsrcMosEtp335">
<title>&gt; Reconnaître les prépositions</title>
</item>
<item identifier="MosEtp558" identifierref="rsrcMosEtp558">
<title>&gt; Reconnaître les déterminants</title>
</item>
</item>
</item>
<!-- ... -->
</organization>
```
</details>
**Données à extraire :**
- [x] ID -\> attribut `identifier`
- [x] Titre -\> élément `<title>`
- [x] Descendants dans l'arbre -\> éléments `<item>`
---
## Sous-parties
On appelle sous-parties les parties de dernier niveau, les "feuilles" de l'arborescence. Dans le panneau de gauche, ce sont les éléments non dépliables _(ex: "Reconnaître les syllabes en anglais oral")_. Une sous-partie contient plusieurs **activités**, dont la première est affichée quand on sélectionne la sous-partie. Une sous-partie est décrite dans un fichier `sco/MosEtp###`, qui déclare un objet `MosSCO` pour définir son contenu.
```js
oSco = new MosSCO("MosEtp129", "> Reconnaître les syllabes en anglais oral", "MACAO", "MACAO 1 - S'entraîner à la reconnaissance", "", "macao_fusion_ss_barre", "fr");
```
Peu d'infos utiles : nom du fichier, titre (déjà défini dans le `<title>`), titre du "stage" (constant), titre du module parent (déjà connu grâce au manifest), et quelques champs constants.\
Ensuite quelques lignes inutiles, puis on passe à la déclaration des pages.
```js
oSco.tabPages[oSco.tabPages.length] = new PageContenu("Repérer les syllabes orales", "pg861", "exercice", "");
oSco.tabPages[oSco.tabPages.length] = new PageContenu("Repérer les syllabes écrites", "pg60", "exercice", "");
oSco.tabPages[oSco.tabPages.length] = new PageContenu("Commentaire", "pg636", "cours", "");
// ^ titre ^ id ^ type
// [...]
```
Le plus important est l'ID de la page `"pg###"`, et éventuellement le type (`"exercice"` ou `"cours"`), le titre de la page étant déclaré aussi dans la page elle-même.
**Données à extraire :**
- Dans le manifest
- [x] ID -\> attribut `identifier`
- [x] Titre -\> élément `<title>`
- Dans le fichier `MosEtp###.html`
- [~] Titre -\> `<title>`
- [x] Liste des pages (titre, ID) -\> arguments de `new PageContenu()`
---
## Activités, ou pages
Les "unités de navigation". La section centrale de Macao affiche toujours 1 activité, dont le nom est indiqué en haut à droite _(ex: "Repérer les syllabes orales")_. Une activité peut être un cours (sans saisie interactive) ou un des 4 types d'exercices (`QC, QM, TAT, GD` dans `MosMtr/scripts/contenu/ClasseExercice___.js` + `ClasseCours.js`). Elle est décrite dans un fichier `contenu/pages/pg###.html`, qui déclare un objet `Cours` ou `Exercice___` pour définir son contenu.
**Données à extraire (communes à toutes les activités) :**
- [x] Type d'activité -\> premier appel de constructeur `new ___()`
- [x] [Commentaires](#commentaires) -\> éléments `<div id="divCmt___">` dans `<div id="zoneInvisible">`
- [ ] Dans les descriptions, commentaires, blocs HTML divers
- [ ] [Images](#images) -\> éléments `<img id="MosImg###">`
- [ ] Objets Flash -\> appels de fonction `PF_clipAV(...)`
- [ ] Pages d'aide/docs -\> appels de fonction `SCO_ouvrirDoc(...)`
### Cours
Du texte, très souvent des audios, mais parfois aussi des objets Flash spécialisés (voir #11).\
**Quantité :** 59
<details>
<summary>Exemples</summary>
**Exemple de cours simple** : `pg686.html`, mémento _"L'accentuation des auxiliaires"_\
![Screenshot_2024-05-15_15-58-10](uploads/6406297d502d9cd9e05360a6715f631a/Screenshot_2024-05-15_15-58-10.png)\
Exemple de "cours" avec un **exercice en Flash** : `pg455.html`, première page de _"\> Reconnaître les marques de l'accentuation"_\
![Screenshot_2024-05-15_15-57-31](uploads/b967e6b37d1409105e910ea43c786ca3/Screenshot_2024-05-15_15-57-31.png)
</details>
**Données à extraire :**
- [x] Contenu du cours (texte/HTML) -\> élément `<div id="STY_zoneCours">`
### ExerciceQC
_(Question Choix?)_\
Une question avec plusieurs réponses prédéfinies. Existe en variante QCU (une seule bonne réponse) et QCM (plusieurs bonnes réponses).\
**Quantité :** 39 QCU, 9 QCM
<details>
<summary>Exemples</summary>
**Exemple QCU** : `pg381.html`, la première page de _"\> Reconnaître les auxiliaires"_\
![Screenshot_2024-05-15_14-59-01](uploads/bb4795264824c0140f49bb7a2126d5d2/Screenshot_2024-05-15_14-59-01.png)
**Exemple QCM** : `pg8412.html`, page _"Vérifier la place de l'accent primaire (3)"_ dans la sous-partie _"\> Utiliser les marques de l'accentuation"_
Il s'avère que les 9 exercices QCM sont tous dans la même sous-partie, et sont utilisés sémantiquement comme plusieurs QCU : ![Screenshot_2024-05-15_15-22-19](uploads/4be84e866d324dc5205bd1aa0fb808f3/Screenshot_2024-05-15_15-22-19.png)\
Dans cet exemple, on a 3 mots ayant chacun 3 réponses possibles dont 1 bonne, mais l'exercice est implémenté comme un QCM de 9 choix possibles ; on peut tout à fait cocher les 3 choix pour "narrator". C'est un exemple de cas particulier étrange qui devra être corrigé manuellement.
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [x] Choix de réponses
- [x] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = CODE_V` ou `CODE_F` pour chaque valeur de `nr`
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceQM
_(Question Multiple?)_\
Comme ExerciceQC mais avec plusieurs questions, chacune ayant une seule bonne réponse.\
**Quantité :** 8
<details>
<summary>Exemple</summary>
`pg262.html`, la toute première page de Macao 1\
![Screenshot_2024-05-15_14-56-47](uploads/59667940add90fb4f94f55cdb370be6b/Screenshot_2024-05-15_14-56-47.png)
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [ ] Choix de réponses -\> tableau dans `<div id="STY_texteQM">`, chaque ligne (`<tr>`) est une question, chaque cellule de colonne (`<td>`) est une case à cocher. Son `id` indique aussi ses coordonnées (ex: `id="lienRepImg13"` = ligne 1 choix 3)
- [ ] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = '3'` indiquent le numéro du choix correct pour chaque numéro de ligne `nr`
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceTAT
Un texte à trous, avec pour chaque "trou" une liste déroulante de choix de mots.\
**Quantité :** 12
<details>
<summary>Exemple</summary>
`pg20.html`, page _"Ecoutez et complétez (2)"_ dans la sous-partie _"\> Reconnaître les déterminants"_\
![Screenshot_2024-05-15_15-40-29](uploads/23944659726f54961ea79cb4e87d2772/Screenshot_2024-05-15_15-40-29.png)
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [x] Texte avec position des "trous" -\> contenu dans `<div id="STY_texteTAT">`.\
Chaque trou est un élément `<select class="STY_selectTAT" id="champTrou#">` et son numéro est indiqué dans l'`id`.
- [x] Choix pour chaque trou et correction -\> appels `exo.ajouterReponse(index, correction, valeur)`.\
Paramètre "correction" = `ng` pour faux, `nw` pour juste.
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceGD
_(Glisser-Déposer ?)_\
Le plus complexe, avec des objets à glisser et placer librement ou dans des cases.\
**Quantité :** 5
<details>
<summary>Exemple</summary>
`pg545.html`, page _"Compléter une transcription (1)"_ dans _"\> Utiliser les symboles phonétiques"_\
![Screenshot_2024-05-15_15-51-35](uploads/4c4963cf1ea6c82296d9f2022b9a712a/Screenshot_2024-05-15_15-51-35.png)
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [ ] Éléments à déplacer -\> éléments `<div id="exoGDd#">` (le `d` est pour _déplaçable_, et est suivi de son numéro/ID)
- [ ] Cibles de déplacement -\> éléments `<div id="exoGDc#">` (le `c` est pour _cible_, suivi aussi de son numéro/ID)
- [ ] Correction -\> liste de `new PaireGD(deplacable, cible, correct, decalageX, decalageY)` indiquent pour chaque déplaçable sa cible associée et si il est juste (`ng` = faux, `nw` = juste).
- [ ] Positions de tous les éléments -\> offsets CSS `absolute`, sûrement à refaire manuellement.
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### Inutilisés
ExerciceCURS, ExerciceEXP, ExerciceSEQ
---
## Pages d'aide ou "docs"
Dans `contenu/pages/`, les fichiers `*.htm` et `pgd###.html` sont des pages d'aide. Au lieu d'être chargées dans la section centrale, elles peuvent être ouvertes dans une nouvelle fenêtre pop-up avec la fonction `SCO_ouvrirDoc()`, souvent appelée depuis un lien `<a>` dans les pages classiques.
```html
cliquez pour voir la définition d'un <a href="javascript:parent.SCO_ouvrirDoc('pgd171','PAGE')">phonème</a>
```
Ces pages peuvent inclure des objets Flash comme les autres, mais pas d'exercice.
## Contenus des pages
### Commentaires
Certains exercices ont des commentaires, des blocs HTML structurés chargés dans une `<div id="zoneInvisible">`, qui sont déplacés dans la `<div id="STY_zoneCommentaire">` à droite en réponse à certaines actions.
- Commentaire de succès : `<div id="divCmtSucces">`
- Commentaire d'échec : `<div id="divSugg#">`, numérotés à partir de 1
- Autres commentaires : `<div id="divCmt#">`, numérotés à partir de 1, contiennent un petit texte d'aide.
:warning: Les commentaires **peuvent contenir de la mise en forme et des objets Flash** (peut-être même des images ?)
### Images
Les images intégrées dans le contenu d'une page sont reconnaissables par un `id="MosImg###`, à la différence de celles utilisées pour l'UI (boutons). Leur chemin est toujours dans `contenu/media/`.
```html
<img id="MosImg17" src="../media/phon_recognition_54_juste.png">
```
### Objets Flash et audio
TODO
---
# Dans Macao 3
## Modules / Parties
Idem que Macao12 avec `imsmanifest.xml`, mais le nommage devient `seq######`
## Sous-parties
Idem que Macao12, mais le nommage devient `act######`. De même, le fichier `sco/MosEtp###.html` devient `sco/act######.html`.\
Des fichiers XML `sco/md_act######.xml` font leur apparition pour chaque sous-partie, mais contiennent des métadonnées pour SCORM qui ne nous intéressent pas.
À la fin du `imsmanifest.xml`, un tag `<resource ... identifier="rsrcact######" ...>` décrit les dépendances de la sous-partie, sous la forme d'une liste de fichiers : pages `pg###.html`, images, SWFs... Potentiellement utile, ou bien redondant si on les retrouve dans le contenu HTML des pages.
Même format pour le contenu (JavaScript) de la sous-partie, avec `new MosSCO(...)` et presque le même pour les lignes `new PageContenu()`, qui ont ici 6 paramètres string au lieu de 4, le dernier indiquant le type d'activité (`"COURS"`, `"QC"`, `"TAT"`, etc...).
## Activités
Mêmes types d'activités :
```sh
grep -rE --only-matching --no-filename 'new (Cours|Exercice).+;' macao_3/contenu/pages | sort | uniq
```
```
new Cours();
new ExerciceGD();
new ExerciceQC("QCM");
new ExerciceQC("QCU");
new ExerciceQM("QCU");
new ExerciceTAT();
```
Cependant, Macao 3 (ou très probablement MOS Chorus) semble avoir essayé d'obfusquer les définitions des réponses dans le code, peut-être pour éviter qu'un étudiant puisse ouvrir les *devtools* et déduire facilement les réponses correctes. C'est toujours possible en lisant le code (puisque l'appli fonctionne toujours sans serveur), mais complexifié par l'utilisation de techniques... exotiques.
Les sections suivantes sur chaque type d'exercice détaillent ces changements.
### ExerciceQC
L'initialisation des choix ne se base plus sur des indices, mais sur des ID.
- Les éléments HTML des choix (ex: `<div class="STY_reponseQC" id="lienrep627" ...>`) portent chacun un ID de la forme `repX` (la partie `lien` est ignorée et `X` est un nombre).
- À cet élément HTML correspond un objet JS déclaré comme
```js
var oItem = new ItemReponse('rep678');
```
où le paramètre du constructeur est décodé par une fonction `decodeX`, définie [ici](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQC.js#L567), qui remplace les caractères `0 1 2 3 7 8 9` entre eux et conserve les autres. Le résultat est le vrai ID du choix correspondant.
- Cet objet JS est initialisé avec `oItem.init("42", "", "", "");`, où le premier paramètre indique la justesse du choix. Si le dernier caractère est `1`, c'est un choix juste, sinon faux.
- Chaque choix peut être associé à un commentaire de suggestion, de la façon suivante :
```js
var idDet = 'divSugg3';
EXO_ajouterCommentaire(idDet, "", "", "", "", "", "", "rep627", "", "", "", "1", "1", "", "", "", "", "");
```
Le premier paramètre est l'ID du commentaire, le huitième est l'ID du choix.
À la vérification, si la réponse de l'utilisateur est incorrecte, l'application affiche le commentaire d'un des choix sélectionnés ; les commentaires des choix justes sont prioritaires, le reste de la sélection est arbitraire (ex: si 1 choix juste et 1 choix faux sont cochés, le commentaire du choix juste sera affiché).
### ExerciceQM
Question Multiple, plusieurs questions (une par ligne) avec les choix en titre de colonne. Il n'y a que 3 ExerciceQM dans Macao3 donc on peut aussi les extraire manuellement.
Idem que pour QC, les indices sont remplacés par des ID obfusqués.
- `oItem = new ItemReponse('rep###')` déclare une "question" qui correspond à une ligne du tableau `<tr id="trReprep###">`
:warning: L'ID est à décoder avec la fonction [`decodeX()`](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQM.js#L452) (ex: `rep991` devient `rep228`)
- `oItem.init("rep###")` déclare la réponse correcte, qui correspond à une colonne `<td id="col###">`
- :warning: L'ID est à décoder avec une *autre* fonction : [`decodeY()`](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQM.js#L485)
### ExerciceTAT
Le texte à trous existe maintenant en variante "sélection" (menu déroulant) et "libre" (champ texte), tous les deux des `new ExerciceTAT()`. La différence semble se remarquer avec des lignes de la forme
```js
exo.tabSelects[exo.tabSelects.length] = '1';
```
qui définissent quels champs sont des sélecteurs (exemple: comparer `pg4487.html` et `pg1919.html`).
Autre changement, le format des réponses. Tous les libellés sont maintenant obfusqués :
```js
exo.ajouterReponse('rep859', '1', '2', "D8ke8k VOX");
exo.ajouterReponse('rep482', '1', '3', "D8ke8k qOX");
exo.ajouterReponse('rep306', '2', '5', "D8ke8k VOX");
exo.ajouterReponse('rep40', '2', '4', "D8ke8k qOX");
```
Heureusement la fonction de décodage `decodeX()` est statique (clé fixe, ne dépend pas d'autres attributs de l'activité) : [source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L774)
Le 2e paramètre indique à quel champ appartient la réponse. Le troisième indique la correction, mais ce n'est plus simplement `"ng"` pour faux ou `nw` pour juste, mais une valeur numérique. La logique se passe dans la fonction `exo_ajouterReponse(...)` ([source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L75))
```js
function exo_ajouterReponse(lid, num, correction, txt) {
var res = decodeX(txt); // décodage du libellé
// On a un "decalY" qui est la parité (modulo 2) du nombre de trous + le score total
var decalY = (this.tabChamps.length + this.scoreTotal) % 2;
// On calcule un "reste" à partir du numéro de question et de la valeur de "correction"
var reste = correction - num * 2 - 1;
// On décrémente le "reste" si decalY vaut 1
// or decalY vaut 0 ou 1, donc ça revient à `reste = reste - decalY`
if (decalY == 1) {
reste--;
}
// La réponse est correcte (CODE_V) si le reste vaut -1
if (reste == -1) {
correction = CODE_V;
} else {
correction = CODE_F;
}
this.tabReponses[this.tabReponses.length] = new ChampTrou(lid, num, res, correction);
}
```
La réponse ajoutée est correcte si le `reste` vaut -1.
```
reste == -1
correction - 2*num - decalY - 1 == -1
correction - 2*num - decalY == 0
correction == 2*num + decalY
correction == 2*num + (nChamps + scoreTotal) % 2
```
On a donc besoin d'extraire en plus le nombre de champs et le `scoreTotal` pour déterminer si chaque réponse est vraie ou fausse.
### ExerciceGD
Il n'y a qu'un seul ExerciceGD dans macao_3, plus simple à extraire manuellement.
\ No newline at end of file
Cette page décrit la structure de Macao-Legacy et l'emplacement des données de contenu.
*À plusieurs reprises, on a besoin de décrire un motif de nommage : dans ces cas, le caractère `#` correspond à un chiffre, et `_` à n'importe quel caractère alphanumérique. Quand ces caractères sont répétés, ils décrivent par défaut un champ de longueur variable (exemple: `###` désigne de 1 à 3 chiffres)*
---
**Modules** : Macao est composé de 3 modules (Macao 1, 2 et 3). Macao 1 et 2 partagent la même base de code `macao_12`, Macao 3 a été développé plus tard et réside dans `macao_3`.
[[_TOC_]]
# Dans Macao 1 et 2 :
![Macao_12_concepts_annotation](uploads/3d911416917cd59c2e27ae0ca0c80309/Screenshot_2024-08-15_17-17-18.png)
![class_diagram.drawio.svg](uploads/a8e9b401c9a8d8b1927ee88b2b00f4b4/class_diagram.drawio.svg)
---
## Parties
Un module contient une ou plusieurs parties _(ex: "Reconnaître les syllabes")_, qui elles-mêmes peuvent contenir d'autres (sous-)parties. Côté code, une partie a la même représentation qu'un module, c'est un élément sans contenu propre, décrit seulement dans le manifeste [`imsmanifest.xml`](https://gitlab.tetras-libre.fr/macao/macao-legacy/-/blob/main/Basilisk/MACAO/macao_12/imsmanifest.xml)
<details>
<summary>Exemple XML</summary>
```xml
<organization>
<!-- ... -->
<item identifier="MosMod10"> <!-- module "MosMod10" -->
<title>MACAO 1 - S'entraîner à la reconnaissance</title> <!-- titre de MosMod10 -->
<!-- Contenu de MosMod10 -->
<item identifier="MosMod11">
<title>Reconnaître les syllabes</title>
<!-- Contenu de MosMod11 -->
<item identifier="MosEtp129" identifierref="rsrcMosEtp129">
<!-- Sous-partie "MosEtp129", contenu défini dans MosEtp129.html -->
<title>&gt; Reconnaître les syllabes en anglais oral</title>
</item>
</item>
<item identifier="MosMod34">
<title>Reconnaître les auxiliaires, les prépositions et les déterminants</title>
<item identifier="MosEtp210" identifierref="rsrcMosEtp210">
<title>&gt; Reconnaître les auxiliaires</title>
</item>
<item identifier="MosEtp335" identifierref="rsrcMosEtp335">
<title>&gt; Reconnaître les prépositions</title>
</item>
<item identifier="MosEtp558" identifierref="rsrcMosEtp558">
<title>&gt; Reconnaître les déterminants</title>
</item>
</item>
</item>
<!-- ... -->
</organization>
```
</details>
**Données à extraire :**
- [x] ID -\> attribut `identifier`
- [x] Titre -\> élément `<title>`
- [x] Descendants dans l'arbre -\> éléments `<item>`
---
## Sous-parties
On appelle sous-parties les parties de dernier niveau, les "feuilles" de l'arborescence. Dans le panneau de gauche, ce sont les éléments non dépliables _(ex: "Reconnaître les syllabes en anglais oral")_. Une sous-partie contient plusieurs **activités**, dont la première est affichée quand on sélectionne la sous-partie. Une sous-partie est décrite dans un fichier `sco/MosEtp###`, qui déclare un objet `MosSCO` pour définir son contenu.
```js
oSco = new MosSCO("MosEtp129", "> Reconnaître les syllabes en anglais oral", "MACAO", "MACAO 1 - S'entraîner à la reconnaissance", "", "macao_fusion_ss_barre", "fr");
```
Peu d'infos utiles : nom du fichier, titre (déjà défini dans le `<title>`), titre du "stage" (constant), titre du module parent (déjà connu grâce au manifest), et quelques champs constants.\
Ensuite quelques lignes inutiles, puis on passe à la déclaration des pages.
```js
oSco.tabPages[oSco.tabPages.length] = new PageContenu("Repérer les syllabes orales", "pg861", "exercice", "");
oSco.tabPages[oSco.tabPages.length] = new PageContenu("Repérer les syllabes écrites", "pg60", "exercice", "");
oSco.tabPages[oSco.tabPages.length] = new PageContenu("Commentaire", "pg636", "cours", "");
// ^ titre ^ id ^ type
// [...]
```
Le plus important est l'ID de la page `"pg###"`, et éventuellement le type (`"exercice"` ou `"cours"`), le titre de la page étant déclaré aussi dans la page elle-même.
**Données à extraire :**
- Dans le manifest
- [x] ID -\> attribut `identifier`
- [x] Titre -\> élément `<title>`
- Dans le fichier `MosEtp###.html`
- [~] Titre -\> `<title>`
- [x] Liste des pages (titre, ID) -\> arguments de `new PageContenu()`
---
## Activités, ou pages
Les "unités de navigation". La section centrale de Macao affiche toujours 1 activité, dont le nom est indiqué en haut à droite _(ex: "Repérer les syllabes orales")_. Une activité peut être un cours (sans saisie interactive) ou un des 4 types d'exercices (`QC, QM, TAT, GD` dans `MosMtr/scripts/contenu/ClasseExercice___.js` + `ClasseCours.js`). Elle est décrite dans un fichier `contenu/pages/pg###.html`, qui déclare un objet `Cours` ou `Exercice___` pour définir son contenu.
**Données à extraire (communes à toutes les activités) :**
- [x] Type d'activité -\> premier appel de constructeur `new ___()`
- [x] [Commentaires](#commentaires) -\> éléments `<div id="divCmt___">` dans `<div id="zoneInvisible">`
- [ ] Dans les descriptions, commentaires, blocs HTML divers
- [ ] [Images](#images) -\> éléments `<img id="MosImg###">`
- [ ] Objets Flash -\> appels de fonction `PF_clipAV(...)`
- [ ] Pages d'aide/docs -\> appels de fonction `SCO_ouvrirDoc(...)`
### Cours
Du texte, très souvent des audios, mais parfois aussi des objets Flash spécialisés (voir #11).\
**Quantité :** 59
<details>
<summary>Exemples</summary>
**Exemple de cours simple** : `pg686.html`, mémento _"L'accentuation des auxiliaires"_\
![Screenshot_2024-05-15_15-58-10](uploads/6406297d502d9cd9e05360a6715f631a/Screenshot_2024-05-15_15-58-10.png)\
Exemple de "cours" avec un **exercice en Flash** : `pg455.html`, première page de _"\> Reconnaître les marques de l'accentuation"_\
![Screenshot_2024-05-15_15-57-31](uploads/b967e6b37d1409105e910ea43c786ca3/Screenshot_2024-05-15_15-57-31.png)
</details>
**Données à extraire :**
- [x] Contenu du cours (texte/HTML) -\> élément `<div id="STY_zoneCours">`
### ExerciceQC
_(Question Choix?)_\
Une question avec plusieurs réponses prédéfinies. Existe en variante QCU (une seule bonne réponse) et QCM (plusieurs bonnes réponses).\
**Quantité :** 39 QCU, 9 QCM
<details>
<summary>Exemples</summary>
**Exemple QCU** : `pg381.html`, la première page de _"\> Reconnaître les auxiliaires"_\
![Screenshot_2024-05-15_14-59-01](uploads/bb4795264824c0140f49bb7a2126d5d2/Screenshot_2024-05-15_14-59-01.png)
**Exemple QCM** : `pg8412.html`, page _"Vérifier la place de l'accent primaire (3)"_ dans la sous-partie _"\> Utiliser les marques de l'accentuation"_
Il s'avère que les 9 exercices QCM sont tous dans la même sous-partie, et sont utilisés sémantiquement comme plusieurs QCU : ![Screenshot_2024-05-15_15-22-19](uploads/4be84e866d324dc5205bd1aa0fb808f3/Screenshot_2024-05-15_15-22-19.png)\
Dans cet exemple, on a 3 mots ayant chacun 3 réponses possibles dont 1 bonne, mais l'exercice est implémenté comme un QCM de 9 choix possibles ; on peut tout à fait cocher les 3 choix pour "narrator". C'est un exemple de cas particulier étrange qui devra être corrigé manuellement.
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [x] Choix de réponses
- [x] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = CODE_V` ou `CODE_F` pour chaque valeur de `nr`
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceQM
_(Question Multiple?)_\
Comme ExerciceQC mais avec plusieurs questions, chacune ayant une seule bonne réponse.\
**Quantité :** 8
<details>
<summary>Exemple</summary>
`pg262.html`, la toute première page de Macao 1\
![Screenshot_2024-05-15_14-56-47](uploads/59667940add90fb4f94f55cdb370be6b/Screenshot_2024-05-15_14-56-47.png)
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [ ] Choix de réponses -\> tableau dans `<div id="STY_texteQM">`, chaque ligne (`<tr>`) est une question, chaque cellule de colonne (`<td>`) est une case à cocher. Son `id` indique aussi ses coordonnées (ex: `id="lienRepImg13"` = ligne 1 choix 3)
- [ ] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = '3'` indiquent le numéro du choix correct pour chaque numéro de ligne `nr`
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceTAT
Un texte à trous, avec pour chaque "trou" une liste déroulante de choix de mots.\
**Quantité :** 12
<details>
<summary>Exemple</summary>
`pg20.html`, page _"Ecoutez et complétez (2)"_ dans la sous-partie _"\> Reconnaître les déterminants"_\
![Screenshot_2024-05-15_15-40-29](uploads/23944659726f54961ea79cb4e87d2772/Screenshot_2024-05-15_15-40-29.png)
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [x] Texte avec position des "trous" -\> contenu dans `<div id="STY_texteTAT">`.\
Chaque trou est un élément `<select class="STY_selectTAT" id="champTrou#">` et son numéro est indiqué dans l'`id`.
- [x] Choix pour chaque trou et correction -\> appels `exo.ajouterReponse(index, correction, valeur)`.\
Paramètre "correction" = `ng` pour faux, `nw` pour juste.
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceGD
_(Glisser-Déposer ?)_\
Le plus complexe, avec des objets à glisser et placer librement ou dans des cases.\
**Quantité :** 5
<details>
<summary>Exemple</summary>
`pg545.html`, page _"Compléter une transcription (1)"_ dans _"\> Utiliser les symboles phonétiques"_\
![Screenshot_2024-05-15_15-51-35](uploads/4c4963cf1ea6c82296d9f2022b9a712a/Screenshot_2024-05-15_15-51-35.png)
</details>
**Données à extraire :**
- [x] Consigne -\> `<div id="STY_question">`
- [ ] Éléments à déplacer -\> éléments `<div id="exoGDd#">` (le `d` est pour _déplaçable_, et est suivi de son numéro/ID)
- [ ] Cibles de déplacement -\> éléments `<div id="exoGDc#">` (le `c` est pour _cible_, suivi aussi de son numéro/ID)
- [ ] Correction -\> liste de `new PaireGD(deplacable, cible, correct, decalageX, decalageY)` indiquent pour chaque déplaçable sa cible associée et si il est juste (`ng` = faux, `nw` = juste).
- [ ] Positions de tous les éléments -\> offsets CSS `absolute`, sûrement à refaire manuellement.
- [x] Commentaires de succès et d'échec -\> `divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### Inutilisés
ExerciceCURS, ExerciceEXP, ExerciceSEQ
---
## Pages d'aide ou "docs"
Dans `contenu/pages/`, les fichiers `*.htm` et `pgd###.html` sont des pages d'aide. Au lieu d'être chargées dans la section centrale, elles peuvent être ouvertes dans une nouvelle fenêtre pop-up avec la fonction `SCO_ouvrirDoc()`, souvent appelée depuis un lien `<a>` dans les pages classiques.
```html
cliquez pour voir la définition d'un <a href="javascript:parent.SCO_ouvrirDoc('pgd171','PAGE')">phonème</a>
```
Ces pages peuvent inclure des objets Flash comme les autres, mais pas d'exercice.
## Contenus des pages
### Commentaires
Certains exercices ont des commentaires, des blocs HTML structurés chargés dans une `<div id="zoneInvisible">`, qui sont déplacés dans la `<div id="STY_zoneCommentaire">` à droite en réponse à certaines actions.
- Commentaire de succès : `<div id="divCmtSucces">`
- Commentaire d'échec : `<div id="divSugg#">`, numérotés à partir de 1
- Autres commentaires : `<div id="divCmt#">`, numérotés à partir de 1, contiennent un petit texte d'aide.
:warning: Les commentaires **peuvent contenir de la mise en forme et des objets Flash** (peut-être même des images ?)
### Images
Les images intégrées dans le contenu d'une page sont reconnaissables par un `id="MosImg###`, à la différence de celles utilisées pour l'UI (boutons). Leur chemin est toujours dans `contenu/media/`.
```html
<img id="MosImg17" src="../media/phon_recognition_54_juste.png">
```
### Objets Flash et audio
TODO
#### Exercices Flash
Les objets Flash sont parfois utilisés pour implémenter des exercices entiers, comme le choix de syllabes :
![image](uploads/3634072157524afcd20096953f0a3290/image.png){width=594 height=222}
![image](uploads/8c50c72d0b240bfa8518dc9f346d5b71/image.png){width=594 height=477}
(Exemples : MACAO 2, "Reconnaître les marques de l'accentuation")
Ceux-là sont très compliqués à extraire. Pour Macao-Hugo, on peut les réimplémenter sur-mesure ou bien en faire un nouveau type de widget SurveyJS.
---
# Dans Macao 3
## Modules / Parties
Idem que Macao12 avec `imsmanifest.xml`, mais le nommage devient `seq######`
## Sous-parties
Idem que Macao12, mais le nommage devient `act######`. De même, le fichier `sco/MosEtp###.html` devient `sco/act######.html`.\
Des fichiers XML `sco/md_act######.xml` font leur apparition pour chaque sous-partie, mais contiennent des métadonnées pour SCORM qui ne nous intéressent pas.
À la fin du `imsmanifest.xml`, un tag `<resource ... identifier="rsrcact######" ...>` décrit les dépendances de la sous-partie, sous la forme d'une liste de fichiers : pages `pg###.html`, images, SWFs... Potentiellement utile, ou bien redondant si on les retrouve dans le contenu HTML des pages.
Même format pour le contenu (JavaScript) de la sous-partie, avec `new MosSCO(...)` et presque le même pour les lignes `new PageContenu()`, qui ont ici 6 paramètres string au lieu de 4, le dernier indiquant le type d'activité (`"COURS"`, `"QC"`, `"TAT"`, etc...).
## Activités
Mêmes types d'activités :
```sh
grep -rE --only-matching --no-filename 'new (Cours|Exercice).+;' macao_3/contenu/pages | sort | uniq
```
```
new Cours();
new ExerciceGD();
new ExerciceQC("QCM");
new ExerciceQC("QCU");
new ExerciceQM("QCU");
new ExerciceTAT();
```
Cependant, Macao 3 (ou très probablement MOS Chorus) semble avoir essayé d'obfusquer les définitions des réponses dans le code, peut-être pour éviter qu'un étudiant puisse ouvrir les *devtools* et déduire facilement les réponses correctes. C'est toujours possible en lisant le code (puisque l'appli fonctionne toujours sans serveur), mais complexifié par l'utilisation de techniques... exotiques.
Les sections suivantes sur chaque type d'exercice détaillent ces changements.
### ExerciceQC
L'initialisation des choix ne se base plus sur des indices, mais sur des ID.
- Les éléments HTML des choix (ex: `<div class="STY_reponseQC" id="lienrep627" ...>`) portent chacun un ID de la forme `repX` (la partie `lien` est ignorée et `X` est un nombre).
- À cet élément HTML correspond un objet JS déclaré comme
```js
var oItem = new ItemReponse('rep678');
```
où le paramètre du constructeur est décodé par une fonction `decodeX`, définie [ici](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQC.js#L567), qui remplace les caractères `0 1 2 3 7 8 9` entre eux et conserve les autres. Le résultat est le vrai ID du choix correspondant.
- Cet objet JS est initialisé avec `oItem.init("42", "", "", "");`, où le premier paramètre indique la justesse du choix. Si le dernier caractère est `1`, c'est un choix juste, sinon faux.
- Chaque choix peut être associé à un commentaire de suggestion, de la façon suivante :
```js
var idDet = 'divSugg3';
EXO_ajouterCommentaire(idDet, "", "", "", "", "", "", "rep627", "", "", "", "1", "1", "", "", "", "", "");
```
Le premier paramètre est l'ID du commentaire, le huitième est l'ID du choix.
À la vérification, si la réponse de l'utilisateur est incorrecte, l'application affiche le commentaire d'un des choix sélectionnés ; les commentaires des choix justes sont prioritaires, le reste de la sélection est arbitraire (ex: si 1 choix juste et 1 choix faux sont cochés, le commentaire du choix juste sera affiché).
### ExerciceTAT
Le texte à trous existe maintenant en variante "sélection" (menu déroulant) et "libre" (champ texte), tous les deux des `new ExerciceTAT()`. La différence semble se remarquer avec des lignes de la forme
```js
exo.tabSelects[exo.tabSelects.length] = '1';
```
qui définissent quels champs sont des sélecteurs (exemple: comparer `pg4487.html` et `pg1919.html`).
Autre changement, le format des réponses. Tous les libellés sont maintenant obfusqués :
```js
exo.ajouterReponse('rep859', '1', '2', "D8ke8k VOX");
exo.ajouterReponse('rep482', '1', '3', "D8ke8k qOX");
exo.ajouterReponse('rep306', '2', '5', "D8ke8k VOX");
exo.ajouterReponse('rep40', '2', '4', "D8ke8k qOX");
```
Heureusement la fonction de décodage `decodeX()` est statique (clé fixe, ne dépend pas d'autres attributs de l'activité) : [source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L774)
Le 2e paramètre indique à quel champ appartient la réponse. Le troisième indique la correction, mais ce n'est plus simplement `"ng"` pour faux ou `nw` pour juste, mais une valeur numérique. La logique se passe dans la fonction `exo_ajouterReponse(...)` ([source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L75))
```js
function exo_ajouterReponse(lid, num, correction, txt) {
var res = decodeX(txt); // décodage du libellé
// On a un "decalY" qui est la parité (modulo 2) du nombre de trous + le score total
var decalY = (this.tabChamps.length + this.scoreTotal) % 2;
// On calcule un "reste" à partir du numéro de question et de la valeur de "correction"
var reste = correction - num * 2 - 1;
// On décrémente le "reste" si decalY vaut 1
// or decalY vaut 0 ou 1, donc ça revient à `reste = reste - decalY`
if (decalY == 1) {
reste--;
}
// La réponse est correcte (CODE_V) si le reste vaut -1
if (reste == -1) {
correction = CODE_V;
} else {
correction = CODE_F;
}
this.tabReponses[this.tabReponses.length] = new ChampTrou(lid, num, res, correction);
}
```
La réponse ajoutée est correcte si le `reste` vaut -1.
```
reste == -1
correction - 2*num - decalY - 1 == -1
correction - 2*num - decalY == 0
correction == 2*num + decalY
correction == 2*num + (nChamps + scoreTotal) % 2
```
On a donc besoin d'extraire en plus le nombre de champs et le `scoreTotal` pour déterminer si chaque réponse est vraie ou fausse.
\ No newline at end of file