Retravaille l'exercice FDS : boutons, étiquette et récapitulatif
- index : emoji de la carte "Corriger un exercice" ✔️ → ✅ - Boutons de toutes les slides centralisés et uniformisés dans la bottom bar - Slide 1 : encadré "Durée 30 min" remonté au-dessus des trois parties - Slides 3 et 5 : suppression du bouton "Vérifier mes réponses" et blocage du passage à la partie suivante tant que tout n'est pas rempli/relié - Slide 7 : bouton "Terminer l'exercice" (ex "Voir le récapitulatif") réparé, faux pictogrammes remplacés par les vraies images SGH, volet de correction de droite et encadré de résultats supprimés - Slide 8 : encadrés 💡 retirés, boutons déplacés sous le tableau comparatif, bouton "Retour aux exercices" supprimé - Confettis déplacés de la slide 6 vers la slide 8
This commit is contained in:
BIN
data/ghs05-corrosif.jpg
Normal file
BIN
data/ghs05-corrosif.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
data/ghs07-nocif.jpg
Normal file
BIN
data/ghs07-nocif.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
BIN
data/ghs09-environnement.jpg
Normal file
BIN
data/ghs09-environnement.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
@@ -74,6 +74,32 @@
|
|||||||
}
|
}
|
||||||
.back-btn:hover { background: rgba(186,117,23,0.08); }
|
.back-btn:hover { background: rgba(186,117,23,0.08); }
|
||||||
|
|
||||||
|
/* Boutons centralisés dans la bottom bar */
|
||||||
|
.bar-actions {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
.bar-actions .btn {
|
||||||
|
padding: 8px 22px;
|
||||||
|
font-size: 13px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.bar-actions .btn:disabled {
|
||||||
|
opacity: 0.45;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.bar-actions .btn { padding: 7px 14px; font-size: 12px; }
|
||||||
|
.bottom-bar .slide-counter { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
/* BUTTONS */
|
/* BUTTONS */
|
||||||
.btn {
|
.btn {
|
||||||
font-family: 'Syne', sans-serif;
|
font-family: 'Syne', sans-serif;
|
||||||
@@ -568,7 +594,8 @@ select:focus { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px
|
|||||||
background: repeating-linear-gradient(90deg, #1a1a18 0 2px, #fff 2px 4px, #1a1a18 4px 5px, #fff 5px 9px);
|
background: repeating-linear-gradient(90deg, #1a1a18 0 2px, #fff 2px 4px, #1a1a18 4px 5px, #fff 5px 9px);
|
||||||
}
|
}
|
||||||
.lbl-picto-wrap { display: flex; align-items: center; gap: 8px; }
|
.lbl-picto-wrap { display: flex; align-items: center; gap: 8px; }
|
||||||
.pictos { display: flex; gap: 6px; }
|
.pictos { display: flex; gap: 6px; align-items: center; }
|
||||||
|
.ghs-img { width: 42px; height: 42px; object-fit: contain; display: block; }
|
||||||
.ghs {
|
.ghs {
|
||||||
width: 38px; height: 38px; position: relative;
|
width: 38px; height: 38px; position: relative;
|
||||||
border: 2.5px solid #c62828; background: #fff;
|
border: 2.5px solid #c62828; background: #fff;
|
||||||
@@ -651,23 +678,10 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
|
|
||||||
/* ---- SLIDE 7 — encadré de réponse sur le côté de l'étiquette ---- */
|
/* ---- SLIDE 7 — encadré de réponse sur le côté de l'étiquette ---- */
|
||||||
#eti-stage {
|
#eti-stage {
|
||||||
max-width: 980px;
|
max-width: 680px;
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: minmax(0, 1fr) 300px;
|
|
||||||
align-items: start;
|
|
||||||
gap: 16px;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
#eti-stage .label-card { grid-column: 1; grid-row: 1; }
|
|
||||||
#eti-stage .eti-pop,
|
|
||||||
#eti-stage .eti-side-hint { grid-column: 2; grid-row: 1; align-self: start; }
|
|
||||||
#eti-stage .eti-pop { position: relative; inset: auto; left: auto; top: auto; max-width: none; width: 100%; }
|
|
||||||
.eti-side-hint {
|
|
||||||
font-size: 12.5px; color: var(--teal-dark); line-height: 1.5;
|
|
||||||
background: var(--teal-light); border: 1px dashed var(--teal-mid);
|
|
||||||
border-radius: 10px; padding: 12px 14px;
|
|
||||||
}
|
|
||||||
.eti-side-hint[hidden] { display: none; }
|
|
||||||
|
|
||||||
/* ---- SLIDE 7 — récapitulatif : étiquette à gauche, tableau à droite ---- */
|
/* ---- SLIDE 7 — récapitulatif : étiquette à gauche, tableau à droite ---- */
|
||||||
.recap-layout { display: flex; gap: 20px; align-items: flex-start; justify-content: center; width: 100%; max-width: 1120px; }
|
.recap-layout { display: flex; gap: 20px; align-items: flex-start; justify-content: center; width: 100%; max-width: 1120px; }
|
||||||
@@ -678,12 +692,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
@keyframes recapSlideLeft { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: none; } }
|
@keyframes recapSlideLeft { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: none; } }
|
||||||
@keyframes recapSlideRight { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
|
@keyframes recapSlideRight { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
|
||||||
|
|
||||||
@media (max-width: 820px) {
|
|
||||||
#eti-stage { grid-template-columns: 1fr; max-width: 680px; }
|
|
||||||
#eti-stage .eti-pop,
|
|
||||||
#eti-stage .eti-side-hint { grid-column: 1; grid-row: auto; }
|
|
||||||
#eti-stage .label-card { grid-row: auto; }
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
.recap-layout { flex-direction: column; align-items: center; }
|
.recap-layout { flex-direction: column; align-items: center; }
|
||||||
.recap-layout #recap-stage { flex: none; max-width: 560px; width: 100%; }
|
.recap-layout #recap-stage { flex: none; max-width: 560px; width: 100%; }
|
||||||
@@ -709,15 +717,16 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<!-- Progress bar -->
|
<!-- Progress bar -->
|
||||||
<div class="progress-bar"><div class="progress-fill" id="progressFill"></div></div>
|
<div class="progress-bar"><div class="progress-fill" id="progressFill"></div></div>
|
||||||
|
|
||||||
<!-- Phase badge -->
|
|
||||||
<div class="phase-badge" id="phaseBadge" style="display:none"></div>
|
|
||||||
|
|
||||||
<!-- Bottom bar -->
|
<!-- Bottom bar -->
|
||||||
<div class="bottom-bar" id="bottomBar" style="display:none;">
|
<div class="bottom-bar" id="bottomBar" style="display:none;">
|
||||||
<button class="back-btn" id="backBtn" onclick="goBack()" style="display:none;">← Retour</button>
|
<button class="back-btn" id="backBtn" onclick="goBack()" style="display:none;">← Retour</button>
|
||||||
|
<div class="bar-actions" id="barActions"></div>
|
||||||
<div class="slide-counter" id="slideCounter"></div>
|
<div class="slide-counter" id="slideCounter"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Confetti -->
|
||||||
|
<canvas id="confettiCanvas" style="position:fixed;inset:0;pointer-events:none;z-index:150;display:none;"></canvas>
|
||||||
|
|
||||||
<!-- ============ SLIDE 0 — ACCUEIL ============ -->
|
<!-- ============ SLIDE 0 — ACCUEIL ============ -->
|
||||||
<div class="slide active fade-in" id="slide-0">
|
<div class="slide active fade-in" id="slide-0">
|
||||||
<div class="deco-circle" style="width:400px;height:400px;background:var(--amber-light);top:-100px;right:-80px;opacity:0.6;"></div>
|
<div class="deco-circle" style="width:400px;height:400px;background:var(--amber-light);top:-100px;right:-80px;opacity:0.6;"></div>
|
||||||
@@ -726,7 +735,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="hero-label">Certibiocide — Travaux dirigés</div>
|
<div class="hero-label">Certibiocide — Travaux dirigés</div>
|
||||||
<div class="hero-title">FDS, FT<br>& Étiquettes</div>
|
<div class="hero-title">FDS, FT<br>& Étiquettes</div>
|
||||||
<p class="hero-sub">Maîtrisez les trois documents essentiels des produits biocides : fiche de sécurité, fiche technique et étiquetage réglementaire.</p>
|
<p class="hero-sub">Maîtrisez les trois documents essentiels des produits biocides : fiche de sécurité, fiche technique et étiquetage réglementaire.</p>
|
||||||
<button class="btn btn-amber" onclick="goTo(1)">Démarrer le TD →</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -736,6 +744,10 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="section-tag">Déroulé du TD</div>
|
<div class="section-tag">Déroulé du TD</div>
|
||||||
<div class="slide-title">Trois documents, trois usages</div>
|
<div class="slide-title">Trois documents, trois usages</div>
|
||||||
<p class="slide-intro">Vous allez apprendre à localiser une information dans chacun des documents de référence d'un produit biocide.</p>
|
<p class="slide-intro">Vous allez apprendre à localiser une information dans chacun des documents de référence d'un produit biocide.</p>
|
||||||
|
<div class="info-card">
|
||||||
|
<span>⏱️</span>
|
||||||
|
<div>Durée ≈ 30 min. Pour chaque question, sélectionnez la <strong>zone du document</strong> où trouver l'information, puis vérifiez votre score.</div>
|
||||||
|
</div>
|
||||||
<div class="overview-grid">
|
<div class="overview-grid">
|
||||||
<div class="overview-card">
|
<div class="overview-card">
|
||||||
<div class="overview-icon">📄</div>
|
<div class="overview-icon">📄</div>
|
||||||
@@ -753,10 +765,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="overview-sub">Interface directe avec l'utilisateur</div>
|
<div class="overview-sub">Interface directe avec l'utilisateur</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card">
|
|
||||||
<span>⏱️</span>
|
|
||||||
<div>Durée ≈ 30 min. Pour chaque question, sélectionnez la <strong>zone du document</strong> où trouver l'information, puis vérifiez votre score.</div>
|
|
||||||
</div>
|
|
||||||
<div class="identity-card">
|
<div class="identity-card">
|
||||||
<div class="identity-title">👥 Identification du groupe</div>
|
<div class="identity-title">👥 Identification du groupe</div>
|
||||||
<div class="identity-fields">
|
<div class="identity-fields">
|
||||||
@@ -771,7 +779,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
</div>
|
</div>
|
||||||
<div class="identity-error" id="idGroupe-error" hidden>⚠️ Renseignez le nom du stagiaire ou du groupe pour continuer.</div>
|
<div class="identity-error" id="idGroupe-error" hidden>⚠️ Renseignez le nom du stagiaire ou du groupe pour continuer.</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-amber" onclick="startPart1()" style="margin-top:1.5rem;">Commencer la partie 1 →</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ============ SLIDE 2 — FDS INTRO ============ -->
|
<!-- ============ SLIDE 2 — FDS INTRO ============ -->
|
||||||
@@ -784,7 +791,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<span>🎯</span>
|
<span>🎯</span>
|
||||||
<div>Pour chaque question, indiquez dans quelle <strong>rubrique (1 à 16)</strong> trouver la réponse — ou « Absent » si l'information n'y figure pas. Les questions sont mélangées à chaque chargement.</div>
|
<div>Pour chaque question, indiquez dans quelle <strong>rubrique (1 à 16)</strong> trouver la réponse — ou « Absent » si l'information n'y figure pas. Les questions sont mélangées à chaque chargement.</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-amber" onclick="goTo(3)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ============ SLIDE 3 — FDS QUIZ (DRAG & DROP) ============ -->
|
<!-- ============ SLIDE 3 — FDS QUIZ (DRAG & DROP) ============ -->
|
||||||
@@ -796,12 +802,7 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="quiz-list quiz-grid" id="fds-questions"></div>
|
<div class="quiz-list quiz-grid" id="fds-questions"></div>
|
||||||
<div class="dnd-bank" id="fds-bank-right"></div>
|
<div class="dnd-bank" id="fds-bank-right"></div>
|
||||||
</div>
|
</div>
|
||||||
<button class="verify-btn btn-amber" id="fds-verify" onclick="verifyFDS()" disabled>✓ Vérifier mes réponses</button>
|
|
||||||
<div id="fds-result" class="result-message"></div>
|
<div id="fds-result" class="result-message"></div>
|
||||||
<div class="actions-row">
|
|
||||||
<button class="btn btn-outline" onclick="resetFDS()">↺ Recommencer</button>
|
|
||||||
<button class="btn btn-coral" onclick="goTo(4)">Passer à la partie 2 →</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ============ SLIDE 4 — FT INTRO ============ -->
|
<!-- ============ SLIDE 4 — FT INTRO ============ -->
|
||||||
@@ -814,7 +815,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<span>🎯</span>
|
<span>🎯</span>
|
||||||
<div>Indiquez la <strong>section</strong> de la FT où trouver chaque information : Description, Propriétés biocides, Conditionnements, Utilisations — ou « Absent ».</div>
|
<div>Indiquez la <strong>section</strong> de la FT où trouver chaque information : Description, Propriétés biocides, Conditionnements, Utilisations — ou « Absent ».</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-coral" onclick="goTo(5)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ============ SLIDE 5 — FT : RELIER ============ -->
|
<!-- ============ SLIDE 5 — FT : RELIER ============ -->
|
||||||
@@ -827,12 +827,7 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="match-col match-left" id="ft-left"></div>
|
<div class="match-col match-left" id="ft-left"></div>
|
||||||
<div class="match-col match-right" id="ft-right"></div>
|
<div class="match-col match-right" id="ft-right"></div>
|
||||||
</div>
|
</div>
|
||||||
<button class="verify-btn btn-coral" id="ft-verify" onclick="verifyFT()" disabled>✓ Vérifier mes réponses</button>
|
|
||||||
<div id="ft-result" class="result-message"></div>
|
<div id="ft-result" class="result-message"></div>
|
||||||
<div class="actions-row">
|
|
||||||
<button class="btn btn-outline" onclick="resetFT()">↺ Recommencer</button>
|
|
||||||
<button class="btn btn-teal" onclick="goTo(6)">Passer à la partie 3 →</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -846,7 +841,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<span>🎯</span>
|
<span>🎯</span>
|
||||||
<div>Sur une <strong>étiquette réelle</strong> (produit professionnel DÉS'INFECT), <strong>cliquez la zone</strong> qui répond à chaque question : nom commercial, pictogrammes, mention d'avertissement, phrases H, phrases P (EPI, premiers secours, élimination), contenu net et centre antipoison. Chaque clic ouvre la <strong>justification réglementaire</strong> de la zone.</div>
|
<div>Sur une <strong>étiquette réelle</strong> (produit professionnel DÉS'INFECT), <strong>cliquez la zone</strong> qui répond à chaque question : nom commercial, pictogrammes, mention d'avertissement, phrases H, phrases P (EPI, premiers secours, élimination), contenu net et centre antipoison. Chaque clic ouvre la <strong>justification réglementaire</strong> de la zone.</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-teal" onclick="goTo(7)" style="margin-top:1.5rem;">Répondre aux questions →</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ============ SLIDE 7 — ÉTIQUETTE CLIQUABLE (HOTSPOTS) ============ -->
|
<!-- ============ SLIDE 7 — ÉTIQUETTE CLIQUABLE (HOTSPOTS) ============ -->
|
||||||
@@ -911,9 +905,9 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="lbl-picto-wrap">
|
<div class="lbl-picto-wrap">
|
||||||
<span class="hotspot" data-zone="z-picto">
|
<span class="hotspot" data-zone="z-picto">
|
||||||
<span class="pictos">
|
<span class="pictos">
|
||||||
<span class="ghs"><span>🐟</span></span>
|
<img class="ghs-img" src="../data/ghs09-environnement.jpg" alt="Pictogramme SGH09 — danger pour le milieu aquatique">
|
||||||
<span class="ghs"><span>🧪</span></span>
|
<img class="ghs-img" src="../data/ghs05-corrosif.jpg" alt="Pictogramme SGH05 — corrosif">
|
||||||
<span class="ghs excl"><span>!</span></span>
|
<img class="ghs-img" src="../data/ghs07-nocif.jpg" alt="Pictogramme SGH07 — nocif / irritant">
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="hotspot" data-zone="z-mention"><span class="lbl-danger">DANGER</span></span>
|
<span class="hotspot" data-zone="z-mention"><span class="lbl-danger">DANGER</span></span>
|
||||||
@@ -923,21 +917,9 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="lbl-footer">FHER — 2, rue de Sèze, 75009 Paris — Tél. 01 23 45 67 89</div>
|
<div class="lbl-footer">FHER — 2, rue de Sèze, 75009 Paris — Tél. 01 23 45 67 89</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="eti-side-hint" id="eti-side-hint">👉 Cliquez une zone de l'étiquette : sa justification réglementaire s'affiche ici, à côté du bidon.</div>
|
|
||||||
|
|
||||||
<div class="eti-pop" id="eti-pop" hidden>
|
|
||||||
<button class="pop-close" onclick="closeEtiPop()" aria-label="Fermer">×</button>
|
|
||||||
<div class="pop-status" id="pop-status"></div>
|
|
||||||
<div class="pop-title" id="pop-title"></div>
|
|
||||||
<div class="pop-reg" id="pop-reg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="etiquette-result" class="result-message"></div>
|
<div id="etiquette-result" class="result-message"></div>
|
||||||
<div class="actions-row">
|
|
||||||
<button class="btn btn-outline" onclick="resetEtiquette()">↺ Recommencer</button>
|
|
||||||
<button class="btn btn-teal" id="eti-recap-btn" onclick="showEtiRecap()" disabled>Voir le récapitulatif →</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ---- PANNEAU B : synthèse / check-list ---- -->
|
<!-- ---- PANNEAU B : synthèse / check-list ---- -->
|
||||||
@@ -950,11 +932,6 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<div class="eti-stage" id="recap-stage"></div>
|
<div class="eti-stage" id="recap-stage"></div>
|
||||||
<table class="checklist-table" id="checklist-table"></table>
|
<table class="checklist-table" id="checklist-table"></table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions-row">
|
|
||||||
<button class="btn btn-outline" onclick="hideEtiRecap()">← Retour à l'exercice</button>
|
|
||||||
<button class="btn btn-amber" onclick="goTo(8)">Voir la synthèse générale →</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -979,19 +956,10 @@ span.hotspot { display: inline; padding: 0 2px; -webkit-box-decoration-break: cl
|
|||||||
<tr><td><strong>Étiquette</strong></td><td>Dangers essentiels, interface rapide</td><td>À chaque prise du produit</td><td>Tous les utilisateurs</td></tr>
|
<tr><td><strong>Étiquette</strong></td><td>Dangers essentiels, interface rapide</td><td>À chaque prise du produit</td><td>Tous les utilisateurs</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<ul class="tips-list">
|
|
||||||
<li><strong>FDS = Sécurité et dangers</strong> → à consulter AVANT manipulation.</li>
|
|
||||||
<li><strong>FT = Mode d'emploi et applications</strong> → à consulter pour l'utilisation.</li>
|
|
||||||
<li><strong>Étiquette = Interface rapide</strong> → lecture obligatoire avant ouverture du produit.</li>
|
|
||||||
<li>Les trois documents sont <strong>complémentaires</strong>, jamais redondants — chacun cible un besoin et un public différents.</li>
|
|
||||||
</ul>
|
|
||||||
<div class="actions-row">
|
<div class="actions-row">
|
||||||
<button class="btn btn-amber" onclick="exporterPDF()">⬇ Télécharger mes réponses (PDF)</button>
|
<button class="btn btn-amber" onclick="exporterPDF()">⬇ Télécharger mes réponses (PDF)</button>
|
||||||
<a href="correction-fds.html" class="btn btn-outline">✔ Corriger un rendu</a>
|
<a href="correction-fds.html" class="btn btn-outline">✔ Corriger un rendu</a>
|
||||||
</div>
|
|
||||||
<div class="actions-row" style="margin-top:0.5rem;">
|
|
||||||
<button class="btn btn-outline" onclick="restartAll()">↺ Recommencer</button>
|
<button class="btn btn-outline" onclick="restartAll()">↺ Recommencer</button>
|
||||||
<a href="../index.html#formations" class="btn btn-outline">Retour aux exercices</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1093,6 +1061,7 @@ let etiAnswers = {}; // { zoneCible : zoneCliquée en 1re tentative } — p
|
|||||||
let etiFirstTry = {}; // { zoneCible : true si trouvée sans erreur }
|
let etiFirstTry = {}; // { zoneCible : true si trouvée sans erreur }
|
||||||
let etiCurError = false; // une erreur a-t-elle eu lieu sur la question courante
|
let etiCurError = false; // une erreur a-t-elle eu lieu sur la question courante
|
||||||
let etiInit = false; // écouteur de clic posé une seule fois
|
let etiInit = false; // écouteur de clic posé une seule fois
|
||||||
|
let etiRecapShown = false;// panneau récapitulatif affiché (slide 7)
|
||||||
|
|
||||||
function buildEtiquette() {
|
function buildEtiquette() {
|
||||||
etiOrder = shuffleArray(etiZones.map((_, i) => i));
|
etiOrder = shuffleArray(etiZones.map((_, i) => i));
|
||||||
@@ -1107,9 +1076,10 @@ function buildEtiquette() {
|
|||||||
closeEtiPop();
|
closeEtiPop();
|
||||||
const r = document.getElementById('etiquette-result');
|
const r = document.getElementById('etiquette-result');
|
||||||
r.className = 'result-message'; r.innerHTML = '';
|
r.className = 'result-message'; r.innerHTML = '';
|
||||||
document.getElementById('eti-recap-btn').disabled = true;
|
etiRecapShown = false;
|
||||||
document.getElementById('eti-exercise').style.display = 'flex';
|
document.getElementById('eti-exercise').style.display = 'flex';
|
||||||
document.getElementById('eti-recap').style.display = 'none';
|
document.getElementById('eti-recap').style.display = 'none';
|
||||||
|
if (currentSlide === 7) renderBarActions();
|
||||||
|
|
||||||
if (!etiInit) {
|
if (!etiInit) {
|
||||||
card.addEventListener('click', onEtiClick);
|
card.addEventListener('click', onEtiClick);
|
||||||
@@ -1136,11 +1106,8 @@ function onEtiClick(e) {
|
|||||||
if (!hs) return;
|
if (!hs) return;
|
||||||
const clicked = hs.dataset.zone;
|
const clicked = hs.dataset.zone;
|
||||||
|
|
||||||
// Exploration libre une fois l'exercice terminé
|
// Exercice terminé : plus d'interaction (les corrections sont dans la correction générale)
|
||||||
if (etiPos >= etiOrder.length) {
|
if (etiPos >= etiOrder.length) return;
|
||||||
openEtiPop(hs, 'info', clicked);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = etiZones[etiOrder[etiPos]];
|
const target = etiZones[etiOrder[etiPos]];
|
||||||
if (clicked === target.zone) {
|
if (clicked === target.zone) {
|
||||||
@@ -1148,7 +1115,6 @@ function onEtiClick(e) {
|
|||||||
hs.classList.add('hs-correct');
|
hs.classList.add('hs-correct');
|
||||||
if (etiAnswers[target.zone] === undefined) etiAnswers[target.zone] = clicked;
|
if (etiAnswers[target.zone] === undefined) etiAnswers[target.zone] = clicked;
|
||||||
etiFirstTry[target.zone] = !etiCurError;
|
etiFirstTry[target.zone] = !etiCurError;
|
||||||
openEtiPop(hs, 'ok', clicked);
|
|
||||||
etiPos++;
|
etiPos++;
|
||||||
etiCurError = false;
|
etiCurError = false;
|
||||||
renderEtiQuestion();
|
renderEtiQuestion();
|
||||||
@@ -1160,14 +1126,12 @@ function onEtiClick(e) {
|
|||||||
hs.classList.remove('hs-wrong'); void hs.offsetWidth; // relance l'animation
|
hs.classList.remove('hs-wrong'); void hs.offsetWidth; // relance l'animation
|
||||||
hs.classList.add('hs-wrong');
|
hs.classList.add('hs-wrong');
|
||||||
setTimeout(() => hs.classList.remove('hs-wrong'), 700);
|
setTimeout(() => hs.classList.remove('hs-wrong'), 700);
|
||||||
openEtiPop(hs, 'ko', clicked);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishEtiquette() {
|
function finishEtiquette() {
|
||||||
const correct = etiZones.filter(z => etiFirstTry[z.zone]).length;
|
const b = document.getElementById('eti-recap-btn');
|
||||||
showScore(document.getElementById('etiquette-result'), correct, etiZones.length);
|
if (b) b.disabled = false;
|
||||||
document.getElementById('eti-recap-btn').disabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Info-bulle réglementaire positionnée près de la zone cliquée */
|
/* Info-bulle réglementaire positionnée près de la zone cliquée */
|
||||||
@@ -1243,6 +1207,8 @@ function showEtiRecap() {
|
|||||||
|
|
||||||
document.getElementById('eti-exercise').style.display = 'none';
|
document.getElementById('eti-exercise').style.display = 'none';
|
||||||
document.getElementById('eti-recap').style.display = 'flex';
|
document.getElementById('eti-recap').style.display = 'flex';
|
||||||
|
etiRecapShown = true;
|
||||||
|
renderBarActions();
|
||||||
|
|
||||||
// Animation : l'étiquette glisse à gauche, le tableau apparaît à sa droite
|
// Animation : l'étiquette glisse à gauche, le tableau apparaît à sa droite
|
||||||
const rl = document.getElementById('recap-layout');
|
const rl = document.getElementById('recap-layout');
|
||||||
@@ -1255,6 +1221,8 @@ function showEtiRecap() {
|
|||||||
function hideEtiRecap() {
|
function hideEtiRecap() {
|
||||||
document.getElementById('eti-recap').style.display = 'none';
|
document.getElementById('eti-recap').style.display = 'none';
|
||||||
document.getElementById('eti-exercise').style.display = 'flex';
|
document.getElementById('eti-exercise').style.display = 'flex';
|
||||||
|
etiRecapShown = false;
|
||||||
|
renderBarActions();
|
||||||
const sa = document.querySelector('#slide-7 .scroll-area');
|
const sa = document.querySelector('#slide-7 .scroll-area');
|
||||||
if (sa) sa.scrollTop = 0;
|
if (sa) sa.scrollTop = 0;
|
||||||
}
|
}
|
||||||
@@ -1296,7 +1264,7 @@ function buildFtMatch() {
|
|||||||
|
|
||||||
initFtMatch();
|
initFtMatch();
|
||||||
document.getElementById('ft-svg').innerHTML = '';
|
document.getElementById('ft-svg').innerHTML = '';
|
||||||
document.getElementById('ft-verify').disabled = true;
|
refreshFtState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetFT() {
|
function resetFT() {
|
||||||
@@ -1354,7 +1322,8 @@ function refreshFtState() {
|
|||||||
dot.closest('.match-item').classList.toggle('connected', used);
|
dot.closest('.match-item').classList.toggle('connected', used);
|
||||||
});
|
});
|
||||||
const all = ftQuestions.every(q => ftConnections[q.id] != null);
|
const all = ftQuestions.every(q => ftConnections[q.id] != null);
|
||||||
document.getElementById('ft-verify').disabled = !all;
|
const btn = document.getElementById('ft-next');
|
||||||
|
if (btn) btn.disabled = !all;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initFtMatch() {
|
function initFtMatch() {
|
||||||
@@ -1474,7 +1443,8 @@ function initFdsDnd() {
|
|||||||
function updateFdsGate() {
|
function updateFdsGate() {
|
||||||
const slots = document.querySelectorAll('#slide-3 .drop-slot');
|
const slots = document.querySelectorAll('#slide-3 .drop-slot');
|
||||||
const all = Array.from(slots).every(s => (s.dataset.value || '') !== '');
|
const all = Array.from(slots).every(s => (s.dataset.value || '') !== '');
|
||||||
document.getElementById('fds-verify').disabled = !all;
|
const btn = document.getElementById('fds-next');
|
||||||
|
if (btn) btn.disabled = !all;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wireVerifyGate(containerId, btnId) {
|
function wireVerifyGate(containerId, btnId) {
|
||||||
@@ -1676,6 +1646,7 @@ function goTo(n) {
|
|||||||
const sa = next.querySelector('.scroll-area');
|
const sa = next.querySelector('.scroll-area');
|
||||||
if (sa) sa.scrollTop = 0;
|
if (sa) sa.scrollTop = 0;
|
||||||
updateUI();
|
updateUI();
|
||||||
|
if (n === 8) setTimeout(launchConfetti, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
@@ -1691,20 +1662,73 @@ function goBack() {
|
|||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Boutons centralisés dans la bottom bar, un jeu par slide */
|
||||||
|
function barBtn(bar, html, cls, fn, opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
const b = document.createElement('button');
|
||||||
|
b.className = 'btn ' + cls;
|
||||||
|
b.innerHTML = html;
|
||||||
|
if (opts.id) b.id = opts.id;
|
||||||
|
if (opts.disabled) b.disabled = true;
|
||||||
|
b.addEventListener('click', fn);
|
||||||
|
bar.appendChild(b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderBarActions() {
|
||||||
|
const bar = document.getElementById('barActions');
|
||||||
|
if (!bar) return;
|
||||||
|
bar.innerHTML = '';
|
||||||
|
switch (currentSlide) {
|
||||||
|
case 0:
|
||||||
|
barBtn(bar, 'Démarrer le TD →', 'btn-amber', () => goTo(1));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
barBtn(bar, 'Commencer la partie 1 →', 'btn-amber', startPart1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
barBtn(bar, 'Répondre aux questions →', 'btn-amber', () => goTo(3));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
barBtn(bar, '↺ Recommencer', 'btn-outline', resetFDS);
|
||||||
|
barBtn(bar, 'Passer à la partie 2 →', 'btn-coral', () => goTo(4), { id: 'fds-next' });
|
||||||
|
updateFdsGate();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
barBtn(bar, 'Répondre aux questions →', 'btn-coral', () => goTo(5));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
barBtn(bar, '↺ Recommencer', 'btn-outline', resetFT);
|
||||||
|
barBtn(bar, 'Passer à la partie 3 →', 'btn-teal', () => goTo(6), { id: 'ft-next' });
|
||||||
|
refreshFtState();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
barBtn(bar, 'Répondre aux questions →', 'btn-teal', () => goTo(7));
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
if (etiRecapShown) {
|
||||||
|
barBtn(bar, '← Retour à l\'exercice', 'btn-outline', hideEtiRecap);
|
||||||
|
barBtn(bar, 'Voir la synthèse générale →', 'btn-amber', () => goTo(8));
|
||||||
|
} else {
|
||||||
|
barBtn(bar, '↺ Recommencer', 'btn-outline', resetEtiquette);
|
||||||
|
barBtn(bar, 'Terminer l\'exercice →', 'btn-teal', showEtiRecap,
|
||||||
|
{ id: 'eti-recap-btn', disabled: etiPos < etiOrder.length });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
// Boutons placés sous le tableau comparatif, dans la slide (pas dans la bottom bar)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateUI() {
|
function updateUI() {
|
||||||
document.getElementById('progressFill').style.width =
|
document.getElementById('progressFill').style.width =
|
||||||
currentSlide === 0 ? '0%' : ((currentSlide / totalSlides) * 100) + '%';
|
currentSlide === 0 ? '0%' : ((currentSlide / totalSlides) * 100) + '%';
|
||||||
document.getElementById('slideCounter').textContent =
|
document.getElementById('slideCounter').textContent =
|
||||||
currentSlide === 0 ? '' : currentSlide + ' / ' + totalSlides;
|
currentSlide === 0 ? '' : currentSlide + ' / ' + totalSlides;
|
||||||
document.getElementById('bottomBar').style.display = currentSlide === 0 ? 'none' : 'flex';
|
document.getElementById('bottomBar').style.display = 'flex';
|
||||||
document.getElementById('backBtn').style.display = history.length > 0 ? 'block' : 'none';
|
document.getElementById('backBtn').style.display = history.length > 0 ? 'block' : 'none';
|
||||||
|
renderBarActions();
|
||||||
const badge = document.getElementById('phaseBadge');
|
|
||||||
const set = (bg, col, txt) => { badge.style.display = 'block'; badge.style.background = bg; badge.style.color = col; badge.textContent = txt; };
|
|
||||||
if (currentSlide === 2 || currentSlide === 3) set('var(--amber-light)', 'var(--amber-dark)', 'Partie 1 — FDS');
|
|
||||||
else if (currentSlide === 4 || currentSlide === 5) set('var(--coral-light)', 'var(--coral)', 'Partie 2 — FT');
|
|
||||||
else if (currentSlide === 6 || currentSlide === 7) set('var(--teal-light)', 'var(--teal-dark)', 'Partie 3 — Étiquette');
|
|
||||||
else badge.style.display = 'none';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function restartAll() {
|
function restartAll() {
|
||||||
@@ -1719,6 +1743,79 @@ function restartAll() {
|
|||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ======================== CONFETTIS ======================== */
|
||||||
|
function launchConfetti() {
|
||||||
|
const canvas = document.getElementById('confettiCanvas');
|
||||||
|
if (!canvas) return;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
canvas.style.display = 'block';
|
||||||
|
|
||||||
|
const colors = ['#BA7517', '#D85A30', '#F5DFB8', '#633806', '#F0A855', '#E8C068', '#FF8C5A'];
|
||||||
|
const particles = Array.from({ length: 180 }, () => ({
|
||||||
|
x: Math.random() * canvas.width,
|
||||||
|
y: -(Math.random() * canvas.height * 0.5),
|
||||||
|
w: Math.random() * 10 + 5,
|
||||||
|
h: Math.random() * 5 + 3,
|
||||||
|
color: colors[Math.floor(Math.random() * colors.length)],
|
||||||
|
rotation: Math.random() * Math.PI * 2,
|
||||||
|
rotSpeed: (Math.random() - 0.5) * 0.18,
|
||||||
|
vx: (Math.random() - 0.5) * 2.5,
|
||||||
|
vy: Math.random() * 3 + 2,
|
||||||
|
opacity: 1,
|
||||||
|
shape: Math.random() < 0.4 ? 'circle' : 'rect'
|
||||||
|
}));
|
||||||
|
|
||||||
|
let rafId;
|
||||||
|
let start = null;
|
||||||
|
const totalDuration = 3800;
|
||||||
|
|
||||||
|
function draw(ts) {
|
||||||
|
if (!start) start = ts;
|
||||||
|
const elapsed = ts - start;
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
let active = false;
|
||||||
|
|
||||||
|
particles.forEach(p => {
|
||||||
|
p.x += p.vx;
|
||||||
|
p.y += p.vy;
|
||||||
|
p.vy += 0.04;
|
||||||
|
p.rotation += p.rotSpeed;
|
||||||
|
p.opacity = elapsed < totalDuration * 0.55
|
||||||
|
? 1
|
||||||
|
: Math.max(0, 1 - (elapsed - totalDuration * 0.55) / (totalDuration * 0.45));
|
||||||
|
|
||||||
|
if (p.y < canvas.height + 20) active = true;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(p.x, p.y);
|
||||||
|
ctx.rotate(p.rotation);
|
||||||
|
ctx.globalAlpha = p.opacity;
|
||||||
|
ctx.fillStyle = p.color;
|
||||||
|
if (p.shape === 'circle') {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(0, 0, p.w / 2, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
} else {
|
||||||
|
ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (active && elapsed < totalDuration * 1.3) {
|
||||||
|
rafId = requestAnimationFrame(draw);
|
||||||
|
} else {
|
||||||
|
canvas.style.display = 'none';
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rafId) cancelAnimationFrame(rafId);
|
||||||
|
rafId = requestAnimationFrame(draw);
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
generateQuizzes();
|
generateQuizzes();
|
||||||
updateUI();
|
updateUI();
|
||||||
|
|||||||
@@ -141,7 +141,7 @@
|
|||||||
<!-- Correction : page unique pour tous les exercices -->
|
<!-- Correction : page unique pour tous les exercices -->
|
||||||
<div class="formation-card">
|
<div class="formation-card">
|
||||||
<div class="formation-header">
|
<div class="formation-header">
|
||||||
<div class="formation-icon">✔️</div>
|
<div class="formation-icon">✅</div>
|
||||||
<h3 class="formation-title">Corriger un exercice</h3>
|
<h3 class="formation-title">Corriger un exercice</h3>
|
||||||
<p class="formation-subtitle">Correction des rendus</p>
|
<p class="formation-subtitle">Correction des rendus</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user