From 25fb3cee7fc3ca3bbc1ad68c857c5c7f91df39bd Mon Sep 17 00:00:00 2001 From: bach Date: Fri, 16 Oct 2026 17:02:38 +0200 Subject: [PATCH] cours 16-10-26 --- intro js by IA/index.html | 1431 +++++++++++++++++++++++++++++++++++++ intro js by IA/script.js | 366 ++++++++++ intro js by IA/style.css | 461 ++++++++++++ intro js/index.html | 17 + intro js/script.js | 101 +++ intro js/style.css | 18 + 6 files changed, 2394 insertions(+) create mode 100644 intro js by IA/index.html create mode 100644 intro js by IA/script.js create mode 100644 intro js by IA/style.css create mode 100644 intro js/index.html create mode 100644 intro js/script.js create mode 100644 intro js/style.css diff --git a/intro js by IA/index.html b/intro js by IA/index.html new file mode 100644 index 0000000..efb79a3 --- /dev/null +++ b/intro js by IA/index.html @@ -0,0 +1,1431 @@ + + + + + + + + + + + + + + Intro JavaScript + + + + + + + + + + + +
+ + + + + + +
+ +
+

Apprendre à coder avec JavaScript

+

+ On part de zéro, on va loin. Chaque exemple est modifiable et + exécutable directement dans la page : lis, change, casse, recommence. +

+
+ Comment utiliser cette page + Dans chaque bloc noir, modifie le code puis clique sur ▶ Exécuter + (ou Ctrl + Entrée). Le bouton ↺ remet l'exemple d'origine. + Tout ce qui suit // est un commentaire : lis-les, ils expliquent tout. +
+
+ + + +
+

00Coder, c'est quoi ?

+ +

+ Un ordinateur est extrêmement rapide mais complètement bête : + il fait exactement ce qu'on lui dit, ligne par ligne, sans jamais deviner ce qu'on + « voulait dire ». Coder, c'est écrire ces instructions dans + un langage précis qu'il comprend. +

+ +

+ JavaScript (JS) est le langage des navigateurs web. Toutes les pages + interactives que tu utilises (menus, formulaires, jeux, cartes…) en contiennent. + Il tourne aussi sur des serveurs (Node.js), dans des applis, des objets connectés… +

+ +

Les 3 couches d'une page web

+
+ ┌────────────┐   ┌────────────┐   ┌────────────────┐
+ │   HTML     │   │    CSS     │   │  JavaScript    │
+ │ le contenu │ + │ l'apparence│ + │ le comportement│
+ │ "un titre" │   │ "en rouge" │   │ "si on clique, │
+ │            │   │            │   │  il grossit"   │
+ └────────────┘   └────────────┘   └────────────────┘
+   index.html       style.css         script.js
+
+ +

Un programme = des instructions, dans l'ordre

+

+ Le code se lit de haut en bas. Chaque ligne est une instruction, + généralement terminée par un point-virgule ;. + Essaie : clique sur Exécuter. +

+ +
+
premier-programme.js +
+ +
+
+ +
+ La console du navigateur + Appuie sur F12 (ou clic droit → Inspecter) puis onglet « Console ». + C'est l'outil n°1 du développeur : on y voit les messages et les erreurs. + Tu peux même y taper du JavaScript directement. +
+
+ + + +
+

01La console & les commentaires

+ +

+ console.log(...) affiche ce qu'on met entre les parenthèses. + C'est ton meilleur ami pour comprendre ce qui se passe dans ton code : + quand quelque chose ne marche pas, on affiche des valeurs pour vérifier. +

+ +
+
console.js +
+ +
+
+ +
+ Bonne pratique + Un bon commentaire explique pourquoi on fait quelque chose, pas seulement + quoi. Le code dit déjà « quoi » ; le commentaire raconte l'intention. +
+
+ + + +
+

02Les variables : des boîtes avec une étiquette

+ +

+ Une variable est une boîte qui porte un nom et contient une valeur. + On la crée (on dit déclare) une fois, puis on l'utilise par son nom. +

+ +
+   let age = 20;
+
+   ┌─────────┐
+   │   20    │  ← la valeur (ce qu'il y a dedans)
+   └─────────┘
+      age        ← l'étiquette (le nom de la variable)
+
+ + + + + + +
Mot-cléPeut-on changer la valeur ?Quand l'utiliser
constNonPar défaut, tout le temps
letOuiQuand la valeur doit évoluer (compteur, score…)
varOuiJamais : ancienne syntaxe, comportements piégeux
+ +
+
variables.js +
+ +
+
+ +

La portée (scope) : où une variable existe

+

+ Une variable déclarée avec let ou const n'existe que + dans le bloc { } où elle est créée. + En dehors, elle est invisible. +

+ +
+
portee.js +
+ +
+
+
+ + + +
+

03Les types de données

+ +

Toute valeur a un type. Les principaux :

+ + + + + + + + + +
TypeExempleC'est quoi
string"bonjour"Du texte (chaîne de caractères)
number42, 3.14Un nombre (entier ou à virgule, avec un point)
booleantrue, falseVrai ou faux
undefinedundefined« Pas encore de valeur »
nullnull« Vide, volontairement »
object{ }, [ ]Une structure qui regroupe des valeurs (chap. 8 et 9)
+ +
+
types.js +
+ +
+
+ +
+ Piège classique + Ce qu'on récupère d'un champ de formulaire est toujours du texte, + même si l'utilisateur tape un nombre. Pense à le convertir avec Number(). +
+
+ + + +
+

04Les opérateurs

+ +
+
operateurs.js +
+ +
+
+ +
+ Exercice — Une pizza coûte 12 €, on en commande 3, et on a un bon de + réduction de 20 %. Calcule et affiche le prix final avec des variables bien nommées. +
+ Voir une solution +
+
solution.js +
+ +
+
+
+
+
+ + + +
+

05Les conditions : prendre des décisions

+ +

+ Un programme doit souvent choisir : si quelque chose est vrai, faire ceci, + sinon faire cela. +

+ +
+             ┌──────────────┐
+             │ age >= 18 ?  │
+             └──────┬───────┘
+           oui ┌────┴────┐ non
+               ▼         ▼
+          "majeur"    "mineur"
+
+ +
+
conditions.js +
+ +
+
+ +

switch : comparer une valeur à plusieurs cas précis

+
+
switch.js +
+ +
+
+
+ + + +
+

06Les boucles : répéter sans se répéter

+ +

+ Afficher les nombres de 1 à 1000 ? On ne va pas écrire 1000 lignes. + Une boucle répète un bloc de code tant qu'une condition est vraie. +

+ +
+
boucles.js +
+ +
+
+ +
+ Exercice : FizzBuzz (un classique des entretiens d'embauche !) — + Affiche les nombres de 1 à 20, mais : remplace les multiples de 3 par « Fizz », + ceux de 5 par « Buzz », et ceux de 3 et 5 par « FizzBuzz ». +
+ Un indice +

Utilise le modulo %. Et teste d'abord le cas « 3 ET 5 »… pourquoi ?

+
+
+ Voir une solution +
+
fizzbuzz.js +
+ +
+
+
+
+
+ + + +
+

07Les fonctions : des recettes réutilisables

+ +

+ Une fonction est un morceau de code auquel on donne un nom, pour + pouvoir le lancer (on dit appeler) autant de fois qu'on veut. + Elle peut recevoir des paramètres (les ingrédients) et + renvoyer un résultat (le plat). +

+ +
+   paramètres          fonction            valeur renvoyée
+   (3, 4)   ───▶  ┌──────────────┐  ───▶      7
+                  │  additionner │
+                  └──────────────┘
+
+ +
+
fonctions.js +
+ +
+
+ +

Les fonctions sont des valeurs

+

+ En JS, une fonction peut être rangée dans une variable, ou passée en + argument à une autre fonction. Une fonction passée ainsi s'appelle un + callback (« rappel »). C'est une idée centrale en JavaScript. +

+ +
+
callbacks.js +
+ +
+
+ +
+ Exercice — Écris une fonction estPair(n) qui renvoie + true ou false, puis une fonction maximum(a, b) + qui renvoie le plus grand des deux nombres. +
+ Voir une solution +
+
solution.js +
+ +
+
+
+
+
+ + + +
+

08Les tableaux : des listes de valeurs

+ +

+ Un tableau (array) range plusieurs valeurs dans l'ordre. + Chaque case a un numéro, l'indice, qui commence à 0. +

+ +
+   const fruits = ["pomme", "kiwi", "poire"];
+
+   indice :    0        1        2
+            ┌───────┬───────┬───────┐
+            │ pomme │ kiwi  │ poire │      fruits.length → 3
+            └───────┴───────┴───────┘
+
+ +
+
tableaux.js +
+ +
+
+ +

Les super-pouvoirs : map, filter, reduce…

+

+ Ces méthodes prennent une fonction (un callback, vu au chapitre 7) + et l'appliquent à chaque élément. Elles ne modifient pas le tableau d'origine : + elles en renvoient un nouveau. C'est le style « moderne » de JS. +

+ +
+
map-filter-reduce.js +
+ +
+
+
+ + + +
+

09Les objets : décrire une chose

+ +

+ Un tableau range des valeurs par position. Un objet les + range par nom : des paires clé: valeur qu'on appelle + propriétés. Idéal pour décrire un utilisateur, un produit, un personnage… +

+ +
+
objets.js +
+ +
+
+ +

Syntaxes modernes très courantes

+
+
moderne.js +
+ +
+
+ +
+ Copie ou référence ? + const b = a; ne copie pas un objet ou un tableau : a + et b désignent alors le même objet. Modifier l'un modifie l'autre. + Pour copier : const b = { ...a }; ou [...a]. +
+
+ + + +
+

10Le DOM : piloter la page avec JS

+ +

+ Quand le navigateur lit le HTML, il construit en mémoire un arbre + d'objets : le DOM (Document Object Model). + JavaScript peut lire et modifier cet arbre… et la page change instantanément à l'écran. +

+ +
+  document
+   └── html
+        ├── head
+        │    └── title
+        └── body
+             ├── h1        ← document.querySelector("h1")
+             └── div.carte ← document.querySelector(".carte")
+                  └── p
+
+ +
+ Note sur les exemples + Dans une vraie page, on cherche les éléments dans document. + Ici, chaque exemple a sa petite zone blanche nommée scene : on écrit + scene.querySelector(...) pour ne toucher qu'elle. Le principe est identique. +
+ +
+
dom.js +
+ +
+
+

Un titre

+
Une boîte
+
  • un
  • deux
  • trois
+ un lien +
+
+ +
+ textContent ou innerHTML ? + innerHTML interprète le texte comme du HTML ("<b>gras</b>" + devient gras). Pratique, mais dangereux avec du texte tapé par un utilisateur : + il pourrait injecter du code (faille « XSS »). Par défaut, utilise textContent. +
+
+ + + +
+

11Les événements : réagir à l'utilisateur

+ +

+ Un événement, c'est quelque chose qui se produit : un clic, une touche + pressée, la souris qui bouge, un formulaire envoyé… On demande au navigateur : + « quand tel événement arrive sur tel élément, exécute cette fonction ». + C'est le rôle de addEventListener (« ajouter un écouteur »). +

+ +
+
evenements.js +
+ +
+
+

+

→ (vide)

+
survole
+
+
+ +

Les événements les plus utiles

+ + + + + + + + + +
ÉvénementSe déclenche quand…
clickon clique
inputla valeur d'un champ change (à chaque frappe)
submitun formulaire est envoyé (penser à e.preventDefault())
keydownune touche est enfoncée (e.key dit laquelle)
mouseenter / mouseleavela souris entre / sort
scrollon fait défiler
DOMContentLoadedle HTML est entièrement chargé
+
+ + + +
+

12L'asynchrone : gérer le temps qui passe

+ +

+ Jusqu'ici, tout s'exécutait instantanément, dans l'ordre. Mais certaines actions + prennent du temps : attendre 2 secondes, télécharger des données + sur internet… JavaScript ne bloque pas la page en attendant : il continue + et revient plus tard quand le résultat est prêt. C'est l'asynchrone. +

+ +
+
timers.js +
+ +
+
+ +

Les promesses et async / await

+

+ Une Promise (promesse) est un objet qui représente un résultat + futur : « je n'ai pas encore la réponse, mais je te promets de te la donner + (ou de te dire que ça a échoué) ». Le mot-clé await permet + d'attendre une promesse, dans une fonction marquée async. +

+ +
+
async-await.js +
+ +
+
+ +

fetch : récupérer des données sur internet

+

+ fetch(url) envoie une requête à un serveur et renvoie une promesse. + On récupère le plus souvent du JSON (chapitre 9). + Ici, on interroge une API de test gratuite (connexion internet nécessaire). +

+ +
+
fetch.js +
+ +
+
  • (rien encore)
+
+
+ + + +
+

13Les classes : des moules à objets

+ +

+ Quand on doit créer beaucoup d'objets du même genre (des ennemis dans un jeu, des + produits dans une boutique…), on écrit un moule : une + classe. Chaque objet fabriqué avec est une instance. + C'est la base de la programmation orientée objet. +

+ +
+
classes.js +
+ +
+
+
+ + + +
+

14Mini-projet : le jeu du nombre mystère

+ +

+ On rassemble tout : variables, conditions, fonctions, DOM, événements. + L'ordinateur choisit un nombre entre 1 et 100 ; le joueur doit le deviner en un minimum + d'essais. Exécute, joue, puis lis le code et améliore-le ! +

+ +
+
jeu.js +
+ +
+
+
+ + + +
+

Clique sur « Exécuter » pour lancer le jeu.

+

Essais :

+
+
+
+ + + +
+

15Et après ?

+ +

Récapitulatif

+ + + + + + + + + +
NotionÀ retenir
Variablesconst par défaut, let si ça change
ComparaisonToujours === et !==
FonctionsPetites, un seul rôle, un nom qui dit ce qu'elles font
Tableauxmap, filter, find, reduce
DOMquerySelector, textContent, classList
ÉvénementsaddEventListener("click", fonction)
Asynchroneasync / await + try / catch
+ +

Comment progresser

+
    +
  • Lis les erreurs : elles disent presque toujours où et pourquoi.
  • +
  • console.log partout quand tu ne comprends pas ce qui se passe.
  • +
  • Découpe : un gros problème = plein de petits problèmes faciles.
  • +
  • Copie moins, tape plus : écrire le code soi-même ancre la mémoire.
  • +
  • Relis script.js de cette page : tu sais maintenant tout lire !
  • +
+ +

Ressources

+
    +
  • MDN Web Docs — la référence, en français
  • +
  • javascript.info — tutoriel complet et clair
  • +
  • p5.js — dessiner et animer avec JS, idéal en école d'art
  • +
  • CodePen — tester HTML/CSS/JS en ligne et partager
  • +
+ +
+ Défi final — Crée ta propre page (un nouveau dossier avec + index.html, style.css, script.js) : une liste de + tâches où l'on peut ajouter une tâche via un champ, la cocher (classe CSS « faite ») + et la supprimer. Tout ce qu'il faut est dans les chapitres 8, 10 et 11. +
+
+ +
+
+ + diff --git a/intro js by IA/script.js b/intro js by IA/script.js new file mode 100644 index 0000000..339967d --- /dev/null +++ b/intro js by IA/script.js @@ -0,0 +1,366 @@ +/* ===================================================================== + script.js — le "moteur" de la page + --------------------------------------------------------------------- + Ce fichier fait fonctionner les éditeurs de code interactifs. + Il est volontairement TRÈS commenté : c'est lui-même un exemple + de vrai code JavaScript. Une fois que tu auras lu les chapitres, + reviens le lire : tu devrais tout comprendre ! + + Ce qu'il fait : + 1. Trouver tous les éditeurs (.bac) de la page + 2. Quand on clique « Exécuter », lancer le code écrit dedans + 3. Intercepter les console.log pour les afficher DANS la page + 4. Traduire les erreurs en français pour aider à comprendre + 5. Surligner dans le menu le chapitre en cours de lecture + 6. Gérer le bouton clair / sombre + ===================================================================== */ + + +/* --------------------------------------------------------------------- + "use strict" active le MODE STRICT : JavaScript devient plus sévère + et signale des erreurs qu'il ignorerait sinon (ex : utiliser une + variable jamais déclarée). C'est une bonne habitude. + --------------------------------------------------------------------- */ +"use strict"; + + +/* ===================================================================== + 1. OUTIL : transformer n'importe quelle valeur en texte lisible + ===================================================================== + console.log("bonjour") est facile à afficher. Mais comment afficher + un tableau [1, 2, 3] ou un objet { nom: "Ada" } ? Cette fonction + regarde le TYPE de la valeur et fabrique un texte adapté. + + Elle renvoie un élément HTML coloré selon le type. + --------------------------------------------------------------------- */ +function formaterValeur(valeur, profondeur = 0) { + // typeof renvoie le type de la valeur sous forme de texte : + // "string", "number", "boolean", "undefined", "object", "function"… + const type = typeof valeur; + + // Un "texte" (string) : au premier niveau on l'affiche tel quel, + // à l'intérieur d'un tableau/objet on l'entoure de guillemets. + if (type === "string") { + return profondeur === 0 ? valeur : `"${valeur}"`; + } + + if (type === "number" || type === "boolean" || type === "bigint") { + return String(valeur); // String(42) → "42" + } + + if (valeur === undefined) return "undefined"; + if (valeur === null) return "null"; + + if (type === "function") { + // valeur.name = le nom de la fonction (vide si anonyme) + return `ƒ ${valeur.name || "(anonyme)"}()`; + } + + // On évite de descendre trop profond (objets imbriqués à l'infini) + if (profondeur > 3) return "…"; + + // Un tableau : Array.isArray est LA façon fiable de le reconnaître, + // car typeof [] renvoie "object" (une bizarrerie historique). + if (Array.isArray(valeur)) { + // .map transforme chaque élément, .join colle le tout avec ", " + const morceaux = valeur.map(v => formaterValeur(v, profondeur + 1)); + return `[${morceaux.join(", ")}]`; + } + + // Un élément HTML (ex : document.querySelector("h1")) + if (valeur instanceof Element) { + const classes = valeur.className ? "." + String(valeur.className).split(" ").join(".") : ""; + return `<${valeur.tagName.toLowerCase()}${valeur.id ? "#" + valeur.id : ""}${classes}>`; + } + + // Une Promise (chapitre asynchrone) + if (valeur instanceof Promise) return "Promise { … }"; + + // Une erreur + if (valeur instanceof Error) return `${valeur.name}: ${valeur.message}`; + + // Un objet "classique" : { cle: valeur, ... } + if (type === "object") { + // Le nom du "constructeur" : utile pour les objets créés avec une classe + const nomClasse = valeur.constructor && valeur.constructor.name !== "Object" + ? valeur.constructor.name + " " + : ""; + // Object.entries({a:1, b:2}) → [["a",1], ["b",2]] + const paires = Object.entries(valeur).map( + ([cle, v]) => `${cle}: ${formaterValeur(v, profondeur + 1)}` + ); + return `${nomClasse}{ ${paires.join(", ")} }`; + } + + return String(valeur); +} + +/* Renvoie le nom d'une classe CSS selon le type, pour colorer la sortie */ +function classeCouleur(valeur) { + if (typeof valeur === "number") return "t-nombre"; + if (typeof valeur === "string") return "t-texte"; + if (typeof valeur === "boolean") return "t-booleen"; + if (valeur === null || valeur === undefined) return "t-vide"; + return ""; +} + + +/* ===================================================================== + 2. OUTIL : traduire les erreurs JavaScript en français + ===================================================================== + Quand le code plante, JavaScript lance une "erreur" avec un nom + (ReferenceError, TypeError…) et un message en anglais. + On ajoute une petite explication pour débutant. + --------------------------------------------------------------------- */ +const EXPLICATIONS_ERREURS = { + // Un objet utilisé comme un "dictionnaire" : nom de l'erreur → explication + ReferenceError: "Tu utilises un nom (variable ou fonction) qui n'existe pas. Faute de frappe ? Variable déclarée plus bas ou dans un autre bloc { } ?", + TypeError: "Tu fais une opération impossible sur ce type de valeur (ex : appeler quelque chose qui n'est pas une fonction, lire une propriété de undefined, modifier une const).", + SyntaxError: "Le code est mal écrit : il manque sans doute une parenthèse, une accolade, un guillemet ou une virgule.", + RangeError: "Une valeur est hors des limites autorisées (souvent : une fonction qui s'appelle elle-même à l'infini).", +}; + +function expliquerErreur(erreur) { + // L'opérateur ?? ("coalescence des nuls") donne la valeur de droite + // si celle de gauche est null ou undefined. + return EXPLICATIONS_ERREURS[erreur.name] ?? ""; +} + + +/* ===================================================================== + 3. UNE "FAUSSE" CONSOLE pour chaque éditeur + ===================================================================== + Le vrai console.log écrit dans les outils de développement (F12). + On fabrique un objet qui a les MÊMES méthodes (log, warn, error…) + mais qui écrit dans la zone .sortie de l'éditeur. + + C'est une "fabrique" : une fonction qui renvoie un objet. + --------------------------------------------------------------------- */ +function creerConsole(zoneSortie) { + + // Fonction interne qui ajoute UNE ligne dans la zone de sortie. + // "...valeurs" (paramètre du reste) récupère TOUS les arguments + // dans un tableau : console.log("a", 1, true) → ["a", 1, true] + function ecrire(niveau, ...valeurs) { + const ligne = document.createElement("div"); // crée un
vide + ligne.className = "ligne " + niveau; + + // Pour chaque valeur, on crée un coloré, séparés par un espace + valeurs.forEach((valeur, index) => { + if (index > 0) ligne.append(" "); + const span = document.createElement("span"); + span.className = classeCouleur(valeur); + // textContent (et pas innerHTML) : le texte est affiché tel quel, + // une balise s'affichera littéralement au lieu d'être interprétée. + span.textContent = formaterValeur(valeur); + ligne.append(span); + }); + + zoneSortie.append(ligne); // ajoute dans la page + zoneSortie.scrollTop = zoneSortie.scrollHeight; // défile tout en bas + + // On envoie AUSSI dans la vraie console du navigateur (F12) + console[niveau === "err" ? "error" : niveau === "warn" ? "warn" : "log"](...valeurs); + } + + // L'objet renvoyé : mêmes noms de méthodes que la vraie console + return { + log: (...v) => ecrire("", ...v), + info: (...v) => ecrire("info", ...v), + warn: (...v) => ecrire("warn", "⚠", ...v), + error: (...v) => ecrire("err", "✖", ...v), + clear: () => { zoneSortie.innerHTML = ""; }, + + // console.table : affiche un tableau d'objets sous forme de lignes + table: (donnees) => { + if (!Array.isArray(donnees)) return ecrire("", donnees); + donnees.forEach((element, i) => ecrire("", `[${i}]`, element)); + }, + }; +} + + +/* ===================================================================== + 4. EXÉCUTER LE CODE d'un éditeur + ===================================================================== + Comment exécuter du texte comme si c'était du code ? + On crée une fonction à partir d'une chaîne de caractères. + + AsyncFunction est le "constructeur" des fonctions async : il permet + d'utiliser "await" directement dans les exemples (chapitre 12). + On passe à cette fonction nos propres "console" et "scene", qui + REMPLACENT les vrais à l'intérieur du code exécuté. + + ⚠ Exécuter du texte comme du code est dangereux avec du texte venant + d'inconnus. Ici, c'est TOI qui écris le code, donc pas de souci. + --------------------------------------------------------------------- */ +const AsyncFunction = (async function () {}).constructor; + +async function executer(bac) { + // querySelector cherche le PREMIER élément correspondant au sélecteur CSS, + // mais seulement À L'INTÉRIEUR de "bac". + const editeur = bac.querySelector("textarea"); + const sortie = bac.querySelector(".sortie"); + const scene = bac.querySelector(".scene"); // peut être null s'il n'y en a pas + + sortie.innerHTML = ""; // on efface l'ancienne sortie + + // Si l'éditeur a une scène, on la remet dans son état de départ. + // (dataset.initial = l'attribut data-initial, rempli au chargement) + if (scene) scene.innerHTML = scene.dataset.initial; + + const maConsole = creerConsole(sortie); + + // try / catch : on "essaie" un bloc de code ; si une erreur survient, + // au lieu de tout planter, on "attrape" l'erreur dans catch. + try { + const fonction = new AsyncFunction("console", "scene", editeur.value); + await fonction(maConsole, scene); + } catch (erreur) { + maConsole.error(`${erreur.name} : ${erreur.message}`); + const aide = expliquerErreur(erreur); + if (aide) maConsole.info("💡 " + aide); + } +} + + +/* ===================================================================== + 5. BRANCHER chaque éditeur : boutons, raccourcis clavier + ===================================================================== + document.querySelectorAll renvoie TOUS les éléments correspondants. + On boucle dessus avec forEach. + --------------------------------------------------------------------- */ +function preparerEditeurs() { + document.querySelectorAll(".bac").forEach((bac) => { + const editeur = bac.querySelector("textarea"); + const scene = bac.querySelector(".scene"); + + // On mémorise le code d'origine pour le bouton « Réinitialiser ». + // .trim() enlève les espaces / retours à la ligne au début et à la fin. + editeur.value = editeur.value.trim(); + const codeOriginal = editeur.value; + + // On mémorise aussi le contenu de départ de la scène + if (scene) scene.dataset.initial = scene.innerHTML; + + // L'éditeur s'adapte à la hauteur de son code + ajusterHauteur(editeur); + editeur.addEventListener("input", () => ajusterHauteur(editeur)); + + // Désactive le correcteur orthographique (inutile pour du code) + editeur.spellcheck = false; + + // --- Bouton « Exécuter » --- + bac.querySelector(".executer").addEventListener("click", () => executer(bac)); + + // --- Bouton « Réinitialiser » --- + bac.querySelector(".reinit").addEventListener("click", () => { + editeur.value = codeOriginal; + ajusterHauteur(editeur); + bac.querySelector(".sortie").innerHTML = ""; + if (scene) scene.innerHTML = scene.dataset.initial; + }); + + // --- Raccourcis clavier dans l'éditeur --- + // L'événement "keydown" se déclenche quand on enfonce une touche. + // L'objet "evenement" décrit la touche (evenement.key) et les + // touches spéciales tenues (ctrlKey, metaKey = Cmd sur Mac…). + editeur.addEventListener("keydown", (evenement) => { + + // Ctrl+Entrée (ou Cmd+Entrée) → exécuter + if (evenement.key === "Enter" && (evenement.ctrlKey || evenement.metaKey)) { + evenement.preventDefault(); // empêche le retour à la ligne + executer(bac); + } + + // Tab → insérer 2 espaces au lieu de quitter le champ + // (Échap puis Tab permet quand même de sortir au clavier) + if (evenement.key === "Tab" && !evenement.shiftKey && !editeur.dataset.sortir) { + evenement.preventDefault(); + const debut = editeur.selectionStart; // position du curseur + const fin = editeur.selectionEnd; + editeur.value = editeur.value.slice(0, debut) + " " + editeur.value.slice(fin); + editeur.selectionStart = editeur.selectionEnd = debut + 2; + } + // Échap : le prochain Tab sortira de l'éditeur (accessibilité clavier) + editeur.dataset.sortir = evenement.key === "Escape" ? "1" : ""; + }); + }); +} + +/* Fait grandir le