Compare commits

1 Commits
main ... main

Author SHA1 Message Date
66df563049 Update R1.02/sae/README.md
Retirer la majuscule parasite qui n'amène pas au fichier mdr
2025-12-30 05:54:49 +01:00
43 changed files with 2 additions and 1717 deletions

View File

@@ -17,7 +17,7 @@ Il donnera lieu à une note en DEV et en COM. Seront jugés :
> - l'url de votre dépot git associé, contenant les sources et le rapport demandé.
> - tous les noms d'étudiants faisant partie du groupe.
**Vérifiez [ici](./Groupes.md) que votre mail a été pris en compte.**
**Vérifiez [ici](./groupes.md) que votre mail a été pris en compte.**
#### Exigences minimales

View File

@@ -15,21 +15,5 @@
- MERIGOT Antoine / SLIMANI Tajeddine / DUCOURE Ibrahim
- GILLET Noa / GUINET Djibril / SALVIA Tim
- Anthony LIROT / Dylan SOYER
- Emile Ta / Imad Mokhtari / Anthony Millerioux / Johan Garnier
- Emile Ta / Imad Mokhtari / Anthony Millerioux
- Matéo POUGET / Nathan LAUNAY / Ender PRADAT-DE CAROLIS
- Fabien SELON / Michaellah LAHIKOA / Koutoub Khan KADARALY
- Clement JACKSON GONZALEZ / Rayane MOUHIB / Dayann Sidiqui
- Jossé Maël / Jihad Ghandri / Jdoudi Abderrahmane
- Antoine BERNARD / Antoine MERCIER / Mathias PLACIDE CONTRERAS
- Amrouchi Youssef / Maël Hamon / Baptiste Lecointre
- Bradney LELIEVRE / Arif MOHAMED
- Salgeiro da silva / Pelini / Janicot
- Kenzo BONNET, Bryan Benhamou, Toni LAURENT
- Mohamed Ouissi / Jabrail Mustaev / Talbi Sofiane
- Aktas / Gobe / Tafok
- CHARRIERE Nicolas / BODOL Mathis / TCHISSAFOU Yann-sulivane
- Matie BAMBA
- Colombani Loïc / Badio Ousmane
- Adrien Jackson-Gonzalez / Gomez / Dimambu-Bola
- Fabien SELON / Michaëllah LAHIKOA / Qoutoub Khan KADARALY
- Kelyan Pierre-Louis / Jordan Arstil / Matheo Salavin-Moura / Evan Giloppé

View File

@@ -1,9 +0,0 @@
## Ressources R4.01 + R4.A.10
#### Semaine 1
[Compléments de javascript](cours/jscomp.pdf) javascript, [tp1](./td_tp/tp1)
#### Semaine 2
[DOM](cours/dom.pdf), [tp2](./td_tp/tp2), [tpmvc](td_tp/tp2mvc)

Binary file not shown.

Binary file not shown.

View File

@@ -1,207 +0,0 @@
# TP javascript : bases du langages.
Un peu [d'aide](./aide.md).
> - seance 1 : [révisions](#p1)
> - seance 2 : [forEach, filter, map, reduce, etc.](#p2)
### <a name="p1"></a> Séance 1
#### Ex1 : fourmi de Langton
Une fourmi, assimilable à un petit automate, se promène sur une grille de points colorés;
pour commencer, tous les points sont blancs.
- la fourmi est initialement placée au centre de la grille. Elle se déplace dans les quatre directions cardinales. Initialement, elle va vers l'est.
- A chaque pas, elle se déplace d'une case dans sa direction. Son parcours est dicté par les deux règles suivantes :
- Si la case atteinte est noire, elle la repeint en blanc, et tourne de 90° à gauche.
- Si la case est blanche, elle la repeint en noire, et tourne de 90° à droite.
- Elle continue son chemin en suivant ces règles.
<div align="center">
_Les 9 premiers pas de la fourmi_<br>
<img src="./img/fourmi.png">
</div>
Vous disposez de [sources](./src/langton) que vous allez compléter. En particulier, il y a 2 modules :
>- une classe **Ant** qui représente l'univers : la fourmi, et les tuiles sur lesquelles elle se déplace.
>- une fonction **render** qui gére l'affichage graphique.
- La fourmi a une position sur la grille, ainsi qu'une direction. La direction sera codée par un entier (angle 0,90,180 ou 270).
- Les tuiles sont repréntées par un tableau à 2 dimensions. Chaque tuile a 2 valeurs possibles (0 ou 1).
1. Complétez le code de la classe `Ant`.
2. Complétez le code de `app.js`.
3. Ajoutez un bouton/lien qui permet de réinitialiser la simulation.
4. Dissociez, en terme de classe/structure, la fourmi de la grille sur laquelle elle évolue, et modifiez le
code en conséquence.
<div align="center">
<img src="./img/langton.png">
</div>
#### Ex2 : fourmi de Langton
On peut complexifier et généraliser la fourmi précédente, et les règles d'évolution de l'automate correspondant : la fourmi, et les tuiles peuvent avoir
un nombre quelconque d'états. Les règles de l'automate sont alors décrites par une table de transition.
Exemple 1 : on donne la table de transition suivante (T désigne la tuile, a la fourmi) à 2 états pour la fourmi, et 2 états pour les tuiles.
| | T: 0 | T: 1 |
|------|-----------|-----------|
| a: 0 | (1,0,1) | (0,90,1) |
| a: 1 | (0,-90,1) | (1,0,1) |
Chaque triplet représente (Ant State Change, Ant Direction Change, Tile State Change). Ainsi,
- (1,90,0) => on incrémente 1 à l'état de la fourmi, 90 à sa direction, et 0 à l'état de la tuile.
- (0,-90,1) => on incrémente 0 à l'état de la fourmi, -90 à sa direction, et 1 à l'état de la tuile.
Les incrémentations se font modulo le nombre d'états possibles.
Avec cet automate, on obtient la figure :
<div align="center">
<img src="./img/langton1.png">
</div>
Par commodité, on note la table de transition précédente simplement :
```
(1,0,1) (0,90,1)
(0,-90,1) (1,0,1)
```
1. Modifiez le code de l'exercice 1 de manière à pouvoir simuler l'automate ci-dessus. Votre solution doit pouvoir permettre une simulation quelconque.
Quelle est la table correspondante à la fourmi de la première partie du tp ?
2. Testez avec
```
(1,90,0) (0,-90,1)
(0,-90,1) (1,90,1)
```
<div align="center">
<img src="./img/langton2.png">
</div>
3. Testez avec
```
(1, 0, 1) (0, 90, 0)
(0, -90, 1) (1, 0, 1)
```
### <a name="p2"></a> Séance 2
#### Ex1
Soit le tableau d'objets suivant :
```js
let customers = [
{
'id': 1,
'f_name': 'Abby',
'l_name': 'Thomas',
'gender': 'M',
'married': true,
'age': 32,
'expense': 500,
'purchased': ['Shampoo', 'Toys', 'Book']
},
{
'id': 2,
'f_name': 'Jerry',
'l_name': 'Tom',
'gender': 'M',
'married': true,
'age': 64,
'expense': 100,
'purchased': ['Stick', 'Blade']
},
{
'id': 3,
'f_name': 'Dianna',
'l_name': 'Cherry',
'gender': 'F',
'married': true,
'age': 22,
'expense': 1500,
'purchased': ['Lipstik', 'Nail Polish', 'Bag', 'Book']
},
{
'id': 4,
'f_name': 'Dev',
'l_name': 'Currian',
'gender': 'M',
'married': true,
'age': 82,
'expense': 90,
'purchased': ['Book']
},
{
'id': 5,
'f_name': 'Maria',
'l_name': 'Gomes',
'gender': 'F',
'married': false,
'age': 7,
'expense': 300,
'purchased': ['Toys']
},
{
'id': 6,
'f_name': 'Homer',
'l_name': 'Simpson',
'gender': 'M',
'married': true,
'age': 39,
'expense': 500,
'purchased': ['Book']
}
];
```
En utilisant les fonctions/méthodes `forEach, filter, map, reduce, some, every, find`, donnez ou calculez :
1. un tableau des client séniors (dont l'âge est plus de 60 ans).
2. un tableau où chaque client possède un nouvel attribut `full_name`.
3. s'il y a un client de moins de 10 ans.
4. le nombre d'acheteurs de livres.
5. la somme totale d'argent dépensé par les clients marriés.
6. Pour chaque produit, la liste (`id`) des acheteurs.
#### Ex2
Ecrire une fonction qui calcule tous les nombres premiers inférieurs à une valeur entière `n` donnée,
en utilisant le [crible d'Erastosthène](https://fr.wikipedia.org/wiki/Crible_d%27%C3%89ratosth%C3%A8ne).
Le version du crible est volontairement "mal écrite" en terme de performance :
```js
let eratosthene1 = n => {
let numbers = Array.from({length : n - 2}, (v,k) => k + 2);
let p ,primes = [];
while(numbers.length){
[p,...numbers] = numbers;
numbers = numbers.filter( k => k%p != 0);
primes = [...primes,p];
}
return primes;
}
```
1. Expliquez précisément ce code. Testez et dites pourquoi qu'il n'est pas efficace.
2. Écrivez une version plus efficace et comparer les temps de calcul. Vous pourrez compléter le code suivant :
```js
let eratosthene = n => {
let primes = [];
let filterArray = []; // tableau qui permet
// de cribler les multiples des nombres
// premiers
for(let i = 2; i <= n; i++){
// TODO
}
return primes;
}
```

View File

@@ -1,115 +0,0 @@
#### Élement d'un document
```js
let x = document.getElementById(MOVE_VAL_ID)
let images = document.querySelectorAll('img')
```
#### Changer le contenu texte d'un élément
```js
document.getElementById('message').textContent = "hello world !"
```
#### Nombre aléatoire
```js
let r=Math.random();
if (r<0.5)
console.log("Face");
else
console.log("Pile");
```
#### Timers
```js
setTimeout(()=>console.log("3 secondes écoulées"),3000);
let i = setInterval(
() => {
let d = (new Date()).toLocaleTimeString();
document.getElementById("time").innerText = d;
},
1000)
setTimeout(()=>clearInterval(i),10000);
```
#### Réponse à un événement
```js
// inline DOM 0
img.onclick = function(){ console.log("clicked !")}
// DOM >= 2
img.addEventListener("click",()=>console.log("clicked"));
```
#### Itération d'un tableau
```js
let a = [1,2,3];
// forEach
a.forEach( elem => console.log(elem));
// for ... of
// valable pour tous les itérables
// Array, Map, Set, String, etc.
for (let elem of a){
console.log(elem);
}
```
#### Tri d'un tableau
```js
const activities = [
{ title: 'Hiking', date: new Date('2019-06-28') },
{ title: 'Shopping', date: new Date('2019-06-10') },
{ title: 'Trekking', date: new Date('2019-06-22') }
]
const sortedActivities = activities.sort((a, b) => b.date - a.date);
```
#### Itération d'un tableau avec map, filter, reduce et find.
```js
// map
const items = ['a', 'b', 'c']
const newArray = items.map((item) => performSomething(item))
const newArray = items.map(performSomething)
// find
const items = [
{ name: 'a', content: { /* ... */ }},
{ name: 'b', content: { /* ... */ }},
{ name: 'c', content: { /* ... */ }}
]
const b = items.find((item) => item.name === 'b')
//reduce
const items = [
{ name: 'a', content: { value: 1 }},
{ name: 'b', content: { value: 2 }},
{ name: 'c', content: { value: 3 }}
]
const count = items.reduce((result, elem ) => result + elem.content.value, 0)
// en decomposant l'objet !
const count = items.reduce((result, { content: { value } }) => result + value, 0)
```
#### Division d'une chaîne de caractères avec split
```js
const str = 'a,b,c,d,e'
const l = str.split(',')
// l = [ "a","b","c","d","e"]
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<script src="eratosthene.js"></script>
</head>
<body>
<main>
<form role="search">
<input name="limit" type="text">
<input type="submit" value="compute">
</form>
<article>
<p>time : <span id="time1"></span></p>
<p>time : <span id="time2"></span></p>
<p id="primes"></p>
</article>
</main>
<script>
document.querySelector("form").addEventListener("submit",ev => {
ev.preventDefault();
let start,end;
start = performance.now();
primes = eratosthene1(ev.target.limit.value);
end = performance.now();
document.getElementById("time1").textContent = end - start;
document.getElementById("primes").textContent = primes;
})
</script>
</body>
</html>

View File

@@ -1,23 +0,0 @@
function eratosthene(n)
{
let primes = [];
let filterArray = [];
for(let i = 2; i <=n; i++){
// TODO
}
return primes;
}
function eratosthene1(n)
{
let numbers = Array.from({length : n - 2}, (v,k) => k + 2);
let p ,primes = [];
while(numbers.length){
[p,...numbers] = numbers;
numbers = numbers.filter( x => x%p != 0);
primes = [...primes,p];
}
return primes;
}

View File

@@ -1,65 +0,0 @@
import render from "./modules/langton-renderer-canvas2d";
import Ant from "./modules/Ant.js";
const options = {
antStateColors : ['red','yellow'],
tileStateColors : ['white','black'],
tileSize : 5
};
// For the view
const STEP_INTERVAL = 5;
const BTN_AUTOPLAY_ID = 'autoplay';
const BTN_NEXT_MOVE_ID = 'next-move';
const MOVE_VAL_ID = 'move-value';
const BTN_PLUS_100_ID = 'plus-100';
let autoplayInterval;
let canvas = document.querySelector("canvas");
canvas.width = window.innerWidth ;
canvas.height = window.innerHeight;
let ant = new Ant(Math.floor(canvas.width / options.tileSize),Math.floor(canvas.height/options.tileSize));
document.getElementById(BTN_AUTOPLAY_ID).addEventListener('click', () => {
if (autoplayInterval) {
return
}
// TODO
});
document.getElementById(BTN_PLUS_100_ID).addEventListener('click', () => {
if (autoplayInterval) {
clearInterval(autoplayInterval);
autoplayInterval = null;
}
// TODO
});
document.getElementById(BTN_NEXT_MOVE_ID).addEventListener('click', () => {
if (autoplayInterval) {
clearInterval(autoplayInterval);
autoplayInterval = null;
}
ant.moveForward();
updateView(ant,canvas,options)
})
function updateView(ant,canvas,options)
{
document.getElementById(MOVE_VAL_ID).textContent = `${ant.move}`;
render(ant,canvas,options);
}
updateView(ant,canvas,options);

View File

@@ -1,8 +0,0 @@
canvas {
position : absolute ;
top : 0;
left : 0;
z-index : -1;
}

View File

@@ -1,42 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1,witdh=device-width">
<title>Fourmi de Langton</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<!--link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.min.css"
-->
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<main>
<h4>
Fourmi de Langton
</h4>
<nav>
<ul>
<li><a href="#" id="next-move">Next</a></li>
<li><a href="#" id="autoplay">Auto</a></li>
<li><a href="#" id="plus-100">+100</a></li>
</ul>
<ul>
<li>
<small>Nombre de mouvements : <span id="move-value"></span></small>
</li>
</ul>
</nav>
</main>
<canvas></canvas>
<script type="module" src="app.js"></script>
</body>
</html>

View File

@@ -1,56 +0,0 @@
class Ant {
x = 0; // position
y = 0;
move = 0;
w = 0; // universe dimensions
h = 0;
direction = 0; // 0 90 180 270
state = 0;
tiles = null;
constructor (w,h)
{
this.tiles = new Array(w).fill(null);
this.tiles.forEach((el,i) => this.tiles[i] = new Array(h).fill(0));
this.w = w;
this.h = h;
this.x = Math.floor(w/2);
this.y = Math.floor(h/2);
}
moveForward()
{
switch (this.direction) {
case 0:
this.x = ((this.x + 1) + this.w) % this.w;
break
case 90:
this.y = ((this.y + 1) + this.h) % this.h;
break
case 180:
this.x = ((this.x - 1) + this.w) % this.w;
break
case 270:
this.y = ((this.y - 1) + this.h) % this.h;
break
}
this.move ++;
this.computeNextState();
}
rotateRight() {
// TODO
}
rotateLeft() {
// TODO
}
computeNextState()
{
// TODO
}
}
export default Ant;

View File

@@ -1,99 +0,0 @@
/**
* render - renders the universe to a 2D canvas.
*
* @param langtonsAnt - the universe.
* @param canvas - The 2D canvas.
* @param options - The rendering options (all optional).
* @returns {undefined} - Nothing is returned.
*/
function render(langtonsAnt, canvas, options) {
// Grab our options.
const {
tileStateColors,
antStateColors,
tileSize
} = options;
// Drawing style.
const backgroundColor = '#FFFFFF';
// Size constants.
const w = canvas.width;
const h = canvas.height;
// Bounds constants.
const gridSizeW = langtonsAnt.tiles.length;
const gridSizeH = langtonsAnt.tiles[0].length;
// We're going to draw each square with a given edge size
const tileSizeW = tileSize;//w / gridSizeW ;
const tileSizeH = tileSize; //h / gridSizeH ;
// Get the drawing context.
var ctx = canvas.getContext('2d');
// Clear the background.
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, w, h);
// Draw the grid.
ctx.strokeStyle='#00000011';
for (let x = 0; x <= gridSizeW; x++) {
ctx.beginPath();
ctx.moveTo(x * tileSizeW , 0);
ctx.lineTo(x * tileSizeW , h);
ctx.closePath();
ctx.stroke();
}
for (let y = 0 ; y <= gridSizeH; y++) {
ctx.beginPath();
ctx.moveTo(0, y * tileSizeH);
ctx.lineTo(w, y * tileSizeH);
ctx.closePath();
ctx.stroke();
}
// Start drawing those tiles.
langtonsAnt.tiles.forEach((tileRow,i) => {
tileRow.forEach((tile,j)=>{
// Get the tile state index.
// Skip state zero tiles (i.e. white tiles)
if (tile !== 0) {
// Set the tile colour, defaulting to grey if it is not set.
ctx.fillStyle = tileStateColors[tile] || '#CCCCCC';
ctx.fillRect(i * tileSizeW + 1, j * tileSizeH +1, tileSizeW - 1, tileSizeH - 1);
}
})
})
// Draw the ant.
var antX = langtonsAnt.x * tileSizeW,
antY = langtonsAnt.y * tileSizeH;
const antState = langtonsAnt.state;
ctx.fillStyle = antStateColors[antState];
// Tranform before we draw the ant, it makes it easier.
//
ctx.save();
ctx.translate(antX + tileSizeW/2, antY+tileSizeH/2);
ctx.rotate((langtonsAnt.direction / 180) * Math.PI);
ctx.beginPath();
ctx.moveTo(-tileSizeW/2, -tileSizeH/2);
ctx.lineTo(tileSizeW/2, 0);
ctx.lineTo(-tileSizeW/2, tileSizeH/2);
ctx.fill();
ctx.closePath();
ctx.restore();
}
export default render;

View File

@@ -1,55 +0,0 @@
# TP javascript : DOM
Un peu [d'aide](./aide.md).
#### Ex0
On stocke dans un objet une liste de favoris :
```js
let favs = [
{
nom:"Google",
url:"http://www.google.fr"
},
{
nom:"Le Monde",
url:"http://www.google.fr"
},
{
nom:"L'Equipe",
url:"http://www.lequipe.fr"
}
];
```
Compléter le fichier `favoris.js` de manière à créer dans la page html la liste de liens
correspondant
![lien}](./img/liens.png?style=centerme)
Il vous faut créer dynamiquement les noeuds nécessaires avec l'api dom de javascript.
#### Ex1
Il s'agit de réaliser une version "simple" du jeu (whac-a-mole)[https://en.wikipedia.org/wiki/Whac-A-Mole].
Le principe du jeu est de frapper à l'aide d'un marteau sur le plus grand nombre
de taupes parmi celles qui sortent pour un temps très limité et aléatoirement
des trous situés sur un panneau de contrôle.
<div align="center">
<img src="./img/mole.png">
</div>
#### Ex2
Vous devez compléter les [sources](./src/ex1) d'un jeu qui consiste à essayer
d'éteindre toutes les lumières d'une grille en utilisant la règle suivante.
Quand on allume/éteint une lumière, on allume/éteint aussi ses voisines.
<div align="center">
<img src="./img/lights.png">
</div>
Chaque lumière, via l'interface dataset, possède un numéro (de 0 à size^2-1).

View File

@@ -1,132 +0,0 @@
#### Selection d'éléments
```js
// le premier
document.querySelector(".box")
// ou tous
document.querySelectorAll(".box")
// avec l'id
document.getElementById("toto")
// selection d'un élément dans un autre
let container = document.querySeletor('.container')
container.querySelector('.box')
```
#### Traverser le dom
```js
var box = document.querySelector(".box")
box.nextElementSibling
box.previousElementSibling
box.parentElement
box.childNodes
```
#### Création/insertion d'éléments
```js
let p = document.createElement('p')
p.textContent="blabla"
document
.getElementById("myDiv")
.appendChild(p)
div.replaceChildren(p)
```
#### Gestionnaire évènementiels
```js
document.querySelector(".button").addEventListener("click", (e) => { /* ... */ })
document.querySelector(".button").addEventListener("mouseenter", (e) => { /* ... */ })
document.addEventListener("keyup", (e) => { /* ... */ })
```
#### window/document prêt
```js
document.addEventListener("DOMContentLoaded",() = > { .....})
// le dom a été construit (on n'attend pas le chargement du css, images, etc.
windon.addEventListener('load',()=>{...})
// le dom est prêt et toutes les ressources ont été chargées.
```
#### dataset
```html
<div id="user" data-id="1234567890" data-user="carinaanand" data-date-of-birth>
Carina Anand
</div>
```
```javascript
const el = document.querySelector("#user");
// el.id === 'user'
// el.dataset.id === '1234567890'
// el.dataset.user === 'carinaanand'
// el.dataset.dateOfBirth === ''
```
#### Local storage
```js
localStorage.setItem('monChat', 'Tom')
let cat = localStorage.getItem('myCat')
localStorage.clear()
```
#### Limiter les appels successifs à une fonction
```js
function debounce(f,wait)
{
let timeout
return function(...args){
clearTimeout(timeout)
timeout=setTimeout(()=>f(...args),wait)
}
}
```
#### Gestion du css depuis le DOM
```js
// Select the first .box and change its text color to #000
document.querySelector(".box").style.color = "#000";
// Set color to #000 and background to red
var box = document.querySelector(".box")
box.style.color = "#000"
box.style.backgroundColor = "red"
// Set all styles at once (and override any existing styles)
box.style.cssText = "color: #000; background-color: red"
// Hide and show an element by changing "display" to block and none
document.querySelector(".box").style.display = "none"
document.querySelector(".box").style.display = "block"
// Add, remove, and the toggle the "focus" class
var box = document.querySelector(".box")
box.classList.add("focus")
box.classList.remove("focus")
box.classList.toggle("focus")
box.classList.add("focus", "highlighted")
box.classList.remove("focus", "highlighted")
box.classList.add("focus", "highlighted")
box.classList.remove("focus", "highlighted")
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<title>Favoris</title>
<script src="./js/favoris.js"></script>
</head>
<body>
<main>
<h1>Favoris</h1>
</main>
</body>
</html>

View File

@@ -1,24 +0,0 @@
let favoris = [
{
nom:"Google" ,
url:"www.google.fr",
img:"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/200px-Google_2015_logo.svg.png"
},
{
nom:"Le Monde",
url:"lemonde.fr",
img:"https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Lemonde_fr_2005_logo.svg/200px-Lemonde_fr_2005_logo.svg.png?uselang=fr"
},
{
nom:"L'Equipe",
url:"www.lequipe.fr",
img:"https://upload.wikimedia.org/wikipedia/commons/thumb/3/32/L%27%C3%89quipe_wordmark.svg/200px-L%27%C3%89quipe_wordmark.svg.png"
}
]
window.addEventListener("load",()=>{
// TODO
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Whack-a-Mole Game</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main>
<div class="game">
<h1>Whack-a-Mole!</h1>
<div class="score-board">
<span>Score: </span><span id="score">0</span>
</div>
<div class="holes">
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole up"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
<div class="hole"><div class="mole"><img src="img/mole2.png"></div></div>
</div>
<button id="startButton">START</button>
</div>
</main>
<script src="script.js"></script>
</body>
</html>

View File

@@ -1,53 +0,0 @@
const holes = document.querySelectorAll('.hole');
const moles = document.querySelectorAll('.mole');
const scoreBoard = document.getElementById('score');
const startButton = document.getElementById('startButton');
let lastHole;
let timeUp = false;
let score = 0;
let duration = 30
function randomTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
function randomHole(holes) {
const idx = Math.floor(Math.random() * holes.length);
const hole = holes[idx];
if (hole === lastHole) {
return randomHole(holes);
}
lastHole = hole;
return hole;
}
function peep() {
const time = randomTime(1000, 1500);
const hole = randomHole(holes);
// TODO
setTimeout(() => {
// TODO
//
}}, time);
}
function startGame() {
scoreBoard.textContent = 0;
score = 0;
timeUp = false;
// TODO
}
function bonk(e) {
// TODO
}
moles.forEach(mole => mole.addEventListener('click', bonk));
startButton.addEventListener('click', startGame);

View File

@@ -1,68 +0,0 @@
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
/* font-family: Arial, sans-serif;*/
}
.game {
text-align: center;
}
.holes {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
width: 400px;
margin: 20px auto;
}
.hole {
width: 100px;
height: 100px;
background : radial-gradient(rgb(150,250,150), #00ee00);
/* background-color: red;/*#8b4513;*/
/* background-image : url('img/mole2.png');*/
position: relative;
border-radius: 50%;
margin: 10px;
overflow: hidden;
}
.mole img{
width: 10px;
height: 10px;
/* background-color: #555;*/
position: absolute;
bottom: -100px;
left: 0px;
/*border-radius: 50%;*/
transition: bottom 0.3s;
}
.mole.up img{
/* background-image : url('img/mole2.png');
background-size:contain;
background-repeat: no-repeat;*/
width:90px;
height:90px;
bottom: 0px;
}
.mole.whacked img {
content: url('img/mole-whacked.png');
/* background-image : url('img/mole-whacked.png');
background-size:contain;
background-repeat: no-repeat;*/
width:90px;
height:90px;
bottom: -20px;
}
.score-board {
font-size: 1.5em;
margin: 20px;
}

View File

@@ -1,71 +0,0 @@
// variables de vue
const button = document.querySelector("input[type=submit]");
const select = document.querySelector("select");
const board = document.querySelector(".board");
const message = document.querySelector("#message");
let lights = null
// state <-> tableau de booléen pour
// stocker l'état des lumières
// neighbors <-> tableau des voisins de chaque lumière
let state = [];
let neighbors = [];
let newBoard = ( (size ) => {
let frag = document.createDocumentFragment()
// TODO
// la fonction crée dans le dom la grille des lumières
board.replaceChildren(frag)
});
let calcNeighbours = ( (size) =>{
let res = [];
for(let i = 0; i < size; i ++){
for(let j = 0; j < size; j++){
let v = [];
v.push(i*size + j);
if ( (j - 1) >= 0) v.push(i*size + j - 1);
if ( (j + 1) < size) v.push(i*size + j + 1);
if ( (i - 1) >= 0) v.push(size*(i-1) + j );
if ( (i + 1) < size) v.push(size*(i+1) + j);
res.push(v)
}
}
return res
});
function play(){
let size = select.value;
newBoard(size);
neighbors = calcNeighbours(size);
lights = document.querySelectorAll(".board span");
state = Array.from({length: size*size}, () => Math.random() < 0.5 ? 1:0);
state.forEach((el,i)=>{
if (el) lights[i].classList.toggle("off");
});
message.textContent = "";
}
// abonnements
document
.querySelector(".board")
.addEventListener("click", ev => {
// TODO
// permet de choisir d'éteindre/allumer une lumière et
// ses voisines
// Il faut en outre detecter la fin de partie
});
button.addEventListener("click",play);
play();

View File

@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<!-- Centered viewport -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<link rel="stylesheet" href="style.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<main>
<h4>Lights</h4>
<p>Le but est d'éteindre l'ensemble des lumières.</p>
<p id="message"></p>
<article>
<div class="board">
<!--div class="row">
<span data-num="0"></span>
<span data-num="1"></span>
<span data-num="2"></span>
</div>
<div class="row">
<span data-num="3"></span>
<span data-num="4"></span>
<span data-num="5"></span>
</div>
<div class="row">
<span data-num="6"></span>
<span data-num="7"></span>
<span data-num="8"></span-->
</div>
</div>
</article>
<div role="group">
<select aria-label="Select size" required>
<option selected value="3">3x3</option>
<option value="2">2x2</option>
<option value="6">6x6</option>
<option value="7">7x7</option>
<option value="8">8x8</option>
<option value="10">10x10</option>
</select>
<input type="submit" value="New Game">
</div>
</main>
<script src="app.js"></script>
</body>
</html>

View File

@@ -1,50 +0,0 @@
/*.grid {
display:grid;
grid-template-columns : 100px 100px 100px;
grid-template-rows: auto;
grid-gap: 10px;
}*/
.board > div {
display : flex;
}
.board span {
display: inline-block;
vertical-align:baseline;
width: 100px;
height: 100px;
/*padding : 1em;*/
margin : 0.1em;
cursor: pointer;
border: 1px solid #444;
border-radius: 50px;
background: radial-gradient(rgb(150,250,150), #00ee00);
}
.board span.off {
background: #009900;
}
.board span.off:hover {
background: #3AB903;
}
.board span:hover {
background: #3AB903;
background: radial-gradient(rgb(66, 255, 66), #065006);
}
/*
.wrapper {
display : flex;
justify-content: space-around;
}
.wrapper .grid {
flex-basis : auto;
}
*/

View File

@@ -1,163 +0,0 @@
#### Ex3 : modele MVC
Le but est d'écrire une todolist en javascript, en respectant le pattern MVC. Il est important de mener à bout cet exercice, car il nous servira
de fil rouge notamment en ajoutant une api rest et ajax pour la communication avec le service.
<div align="center">
<img src="./img/todo.png">
</div>
Le contrôleur a accès à la vue et au modèle.
##### Le modèle
Cette "classe" (rien à compléter) utilise
l'objet [localStorage](https://developer.mozilla.org/fr/docs/Web/API/Window/localStorage)
pour sauvegarder la todolist.
Chaque todo est un objet json de la forme
```js
{ id : 1 , text : "apprendre le js", done : false }
```
La liste des méthodes publiques de cette classe
```js
/** @brief return the todolist
* @param filter "all" or "active" or "done"
* @return array of todos
*/
getTodos(filter)
/** @brief add (and save) a new todo with todoText
* @param todoText : text of the new todo
*/
add(todoText)
/** @brief delete a todo
* @param id id of the todo
*/
delete(id)
/** @brief update a todo
* @param id id of the todo
*/
edit(id,updatedText)
/** @brief toggle a todo (done<->active)
* @param id id of the todo
* @param updatedText text of the todo
*/
toggle(id)
```
##### La vue
Cette "classe" permet au contrôleur de gérer la vue.
Liste des méthodes publiques
```js
/** @brief change the active tab (all,active or done)
* @param filter the active tab (all, active or done)
*/
setFilterTabs(filter)
/** @brief update the todo list with todos
* @param todos array of todo
*/
renderTodoList(todos)
```
Le contrôleur peut s'abonner (notification de la vue au acontrôleur)
aux événements suivants :
add/delete/edit/toggle todo : avec `bind{Add|Delete|Edit|Toggle}Todo`
Ces méthodes d'abonnement prennent en paramètre une fonction du contrôleur qui est appelé par la vue pour lui notifier
une requête.
```js
/** @brief subscribe to add event
* @param handler function(text)
*/
bindAddTodo(handler)
/** @brief suscribe to delete event
* @param handler function(id)
*/
bindDeleteTodo(handler)
/** @brief suscribe to edit event
* @param handler function(id,text)
*/
bindEditTodo(handler)
/** @brief suscribe to toggle event
* @param handler function(id)
*/
bindToggleTodo(handler)
```
##### Le contrôleur
C'est lui qui gére le routage. Il y a trois urls possibles `index.html/#/{all|active|done}` (listener sur l'évenement
dom `hashchange`.
Liste des méthodes
```js
/** @brief get the todolist from the model
* and use the view to render
*/
filterTodoList()
/** @brief binding function called by the view
* to add a new todo
* @param text text of the new todo
*/
addTodo(text)
/** @brief binding function called by the view
* to delete a todo
* @param id id of the todo
*/
deleteTodo(id)
/** @brief binding function to toggle the state
* of a todo
* @param id id of the todo
*/
toggleTodo(id)
/** @brief binding function to change the text
* of a todo
* @param id id of the todo
* @param changedText new text for the todo
*/
editTodo(id,changedText)
```
Par exemple, lorsque l'utilisateur ajoute une todo :
1. la vue est sensible à l'événement de soumission du formulaire,
2. la fonction reflexe récupére le texte saisie,
3. elle appelle la fonction avec laquelle le contrôleur s'est abonné, en lui passant le texte,
4. la fonction du contrôleur `addTodo` récupére le texte,
5. le contrôleur demande au modèle la création d'une nouvelle todo,
6. le contrôleur demande un rafraichissement de la vue.
#### Travail à faire
- Commpléter la méthode privée dans la vue `#createNewTodoElement` qui permet de créer un
nouvel élément dom représentant une todo. Ce qui est attendu est de la forme
```html
<li class="todo" data-id="1">
<label>
<input type="checkbox">
<span>apprendre un peu de javascript</span>
</label>
<i class="fas fa-trash"></i>
</li>
```
- Compléter la méthode `bindDeleteTodo` de la vue.
- Compléter la méthode `bindToggleTodo` de la vue.
- Compléter la méthode `bindEditTodo` de la vue.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -1,63 +0,0 @@
:focus-visible {outline:none;}
.is-active {
color : #8EB901;
}
#add_form > div {
display : flex;
justify-content:space-between;
}
.todo {
display : flex;
align-items: center;
}
.todo checkbox,.todo i {
flex-grow : 0;
flex-shrink : 0;
flex-basis : auto;
}
.todo span {
flex-grow : 1;
flex-shrink : 1;
flex-basis : auto;
}
.todolist {
padding-left: 0;
}
.todolist li {
list-style: none;
padding: var(--pico-form-element-spacing-vertical) 0;
display: flex;
justify-content: space-between;
align-items: center;
}
#todos_filter {
display:flex;
justify-content : center;
}
#todos_filter a {
margin:1em;
}
.todolist i {
cursor: pointer;
}
.todolist li:not(:last-child) {
border-bottom: 1.5px solid var(--pico-form-element-border-color);
}
.todolist > li > label:has(input:checked) {
text-decoration: line-through;
}
footer {
text-align: center;
}

View File

@@ -1,53 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Todo</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" integrity="sha512-q3eWabyZPc1XTCmF+8/LuE1ozpg5xxn7iO89yfSOd5/oKvyqLngoNGsx8jq92Y8eXJ/IRxQbEC+FGSYxtk2oiw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<header>
<h1>To Do List</h1>
</header>
<main>
<article>
<header>
<form id='add_form'>
<fieldset role="group">
<input id="input_todo" type="text" placeholder="Buy milk and eggs...">
<button><i class="fas fa-plus"></i></button>
</fieldset>
<div>
<span>
<a id="active" href="#/active"><i class="far fa-circle"></i></a>
<a id="done" href="#/done"><i class="fas fa-circle"></i></a>
<a id="all" href="#/all"><i class="fas fa-adjust"></i></a>
</span>
<small><span id="count">0</span>/50 characters</small>
</div>
</form>
</header>
<!-- Render todos -->
<ul id="todos_list" class="todolist"></ul>
</article>
</main>
</body>
<script src="js/model.js"></script>
<script src="js/view.js"></script>
<script src="js/controller.js"></script>
</html>

View File

@@ -1,64 +0,0 @@
class Controller {
constructor(model, view) {
this.model = model;
this.view = view;
this.filter = "all";
/** Abonnements à la vue **/
this.view.bindAddTodo(this.addTodo.bind(this));
this.view.bindDeleteTodo(this.deleteTodo.bind(this));
this.view.bindToggleTodo(this.toggleTodo.bind(this));
this.view.bindEditTodo(this.editTodo.bind(this));
/** filtrages par url **/
this.routes = ['all','active','done'];
/** Routage **/
window.addEventListener("load",this.routeChanged.bind(this));
window.addEventListener("hashchange",this.routeChanged.bind(this));
}
routeChanged(){
let route = window.location.hash.replace(/^#\//,'');
this.filter = this.routes.find( r => r === route) || 'all';
this.filterTodoList();
}
filterTodoList () {
let todos = this.model.getTodos(this.filter)
this.view.renderTodoList(todos)
this.view.setFilterTabs(this.filter)
}
addTodo(text) {
this.model.add(text)
this.filterTodoList()
}
deleteTodo(id) {
this.model.delete(parseInt(id))
this.filterTodoList()
}
toggleTodo(id) {
this.model.toggle(parseInt(id))
this.filterTodoList()
}
editTodo(id, text) {
this.model.edit(parseInt(id),text)
this.filterTodoList()
}
}
const model = new Model()
const view = new View()
const app = new Controller(model, view)

View File

@@ -1,48 +0,0 @@
class Model {
constructor() {
this.todos = JSON.parse(localStorage.getItem('todos')) || []
}
#commit(todos) {
localStorage.setItem('todos', JSON.stringify(todos))
}
getTodos(filter){
if (filter === "active")
return this.todos.filter(todo => !todo.done)
if (filter === "done")
return this.todos.filter(todo => todo.done)
return this.todos
}
add(todoText) {
const todo = {
id: this.todos.length > 0 ? this.todos[this.todos.length - 1].id + 1 : 1,
text: todoText,
done : false,
}
this.todos.push(todo)
this.#commit(this.todos)
}
edit(id, updatedText) {
this.todos = this.todos.map(todo =>
todo.id === id ? { id: todo.id, text: updatedText, done: todo.done} : todo
)
this.#commit(this.todos)
}
delete(id) {
this.todos = this.todos.filter(todo => todo.id !== id)
this.#commit(this.todos)
}
toggle(id) {
this.todos = this.todos.map(todo =>
todo.id === id ? { id: todo.id, text: todo.text, done: !todo.done } : todo
)
this.#commit(this.todos)
}
}

View File

@@ -1,83 +0,0 @@
class View {
charLimit = 70;
constructor() {
this.form = document.querySelector("#add_form")
this.input = document.querySelector("#input_todo")
this.list = document.querySelector("#todos_list")
this.tabs = document.querySelectorAll("#add_form span a")
this.loader = document.querySelector("#loader")
this.count = document.querySelector("#count")
this.input.addEventListener("input", (e) => {
if (e.target.value.length >= this.charLimit) {
e.target.value = e.target.value.substring(0,this.charLimit);
}
count.textContent = e.target.value.length;
});
count.nextSibling.textContent = `/${this.charLimit} characters`
}
#getTodo() {
return this.input.value
}
#resetInput() {
this.input.value = ''
count.textContent = 0
}
#createNewTodoElement(todo){
let li = document.createElement("li")
// TODO
return li
}
setFilterTabs(filter){
this.tabs.forEach( tab => {
if (filter === tab.id)
tab.classList.add("is-active")
else
tab.classList.remove("is-active")
})
}
renderTodoList(todos) {
let list = new DocumentFragment()
for (let todo of todos){
list.appendChild(this.#createNewTodoElement(todo))
}
this.list.replaceChildren(list)
}
/** Abonnements événements **/
bindAddTodo(handler) {
this.form.addEventListener("submit", (e=>{
e.preventDefault()
let text = this.#getTodo()
handler(text)
this.#resetInput()
}))
}
bindDeleteTodo(handler) {
// TODO
}
bindEditTodo(handler) {
// TODO
}
bindToggleTodo(handler) {
// TODO
}
}

View File

@@ -4,7 +4,6 @@
| Ressource | Code | Semestre | Notes |
| --------------------------------------------- | ------------- | --------- | -------------- |
| [Développement d'interfaces web](./R1.02) | R1.02 | S1 | ds | |
| [Complément Web - Architecture logicielle](./R4.01_R4.A.10) | R4.01 + R4.A.10 | S4 | projet (1) |