Compare commits

..

31 Commits

Author SHA1 Message Date
88af050bea maj grps 2026-03-21 15:21:09 +01:00
2373233899 maj grps 2026-03-20 14:30:20 +01:00
8239d8024d maj grps 2026-03-20 14:13:50 +01:00
1586d02094 maj grps 2026-03-20 09:29:42 +01:00
2fe4bab887 maj liste cours 2026-03-20 09:28:55 +01:00
eb792edb4d en route 2026-03-20 09:26:06 +01:00
1a450491c6 maj 2026-03-18 14:10:08 +01:00
a472e34bbe todo riot, avec router 2026-03-16 14:22:17 +01:00
0490924e3d api cm 2026-03-13 13:52:08 +01:00
db7896d2de tp6 2026-03-13 12:08:01 +01:00
bd2243e28a groupes projet 2026-03-09 16:11:08 +01:00
1c7d7f636a ajout exo tp5 2026-03-09 14:55:40 +01:00
1fe20f3f3b groupes projet 2026-03-09 09:23:32 +01:00
7f4884a90d typo 2026-02-24 13:36:21 +01:00
532f73309c typo 2026-02-24 13:30:01 +01:00
129a0c321c typo 2026-02-24 13:26:40 +01:00
ef4ddb1420 miniprojet 2026-02-24 11:49:23 +01:00
da6a720f46 riotjs 2026-02-20 12:08:56 +01:00
6d7a783d73 pb directory 2026-02-20 12:05:24 +01:00
6cb1a005fd tp5 2026-02-20 12:04:02 +01:00
d99fa137ec typo 2026-02-16 11:16:10 +01:00
534fc8ace1 exo2 2026-02-16 11:14:11 +01:00
783e91969c js 2026-02-14 20:19:44 +01:00
226c55aca3 oups 2026-02-13 15:41:09 +01:00
755c3d4e2e typo 2026-02-13 11:23:51 +01:00
c875a397ad typo 2026-02-13 11:22:25 +01:00
5034bf1248 image 2026-02-13 11:19:37 +01:00
322c2a7e7f README 2026-02-13 11:17:37 +01:00
7aa9c51104 tp4 2026-02-13 11:16:49 +01:00
324f310e38 tp3 2026-02-06 13:51:12 +01:00
8536d0b1bb tp3 2026-02-06 13:50:53 +01:00
80 changed files with 6022 additions and 1 deletions

BIN
R1.02/cours/js.pdf Normal file

Binary file not shown.

43
R3.01/README.md Normal file
View File

@@ -0,0 +1,43 @@
# Programmation WEB coté serveur R3.01
Ce dépôt contient les ressources utilisées
(cours/td/tp) dans la ressource R3.01.
**Les objectifs**
> Savoir développer une application Web côté serveur, en utilisant le langage PHP.
Les notions suivantes seront abordées :
- Le langage php
On se limitera aux bases du langages. La couche objet sera présenté très succintement.
Toute la suite sera illustré avec PHP.
- Interaction avec le client
URL (Uniform Resource Locator), requêtes, formulaires, transmission des paramètres, des données, etc.
- Applications Web à états
Cookies et sessions
- Organisation de laccès aux données
Bases de données, annuaires, services Web, etc.
- Introduction à la programmation objet en PHP
Introduction au principe MVC
- Sensibilisation à la sécurité des applications web
## Calendrier
| Semaine | Cours | TD/TP |
| ------------------ | -------------------------------------------------------- | ------------------ |
| 1 : 16/03 - 20/03| [Bases du langages](./cours/cm_bases_php.pdf) | |
## Les TPS
#### TP1 : Bases du langage PHP
Le [tp1](./tp/tp1)
permet de se familiariser avec le langage PHP.
À chaque exercice correspond un sous répertoire avec
des fichiers à compléter.

Binary file not shown.

View File

@@ -4,6 +4,19 @@
[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)
[DOM](cours/dom.pdf), [tp2](./td_tp/tp2), [tp2mvc](td_tp/tp2mvc)
#### Semaine 3
[DOM](cours/dom.pdf), [tp3](./td_tp/tp3)
#### Semaine 4
[Promesses, Ajax, API de données](cours/ajax.pdf), [tp4](./td_tp/tp4)
#### Semaine 5
[Programmation déclarative, RIOT.js](cours/riot.pdf), [tp5](./td_tp/tp5)
#### Semaine 6
[API REST](cours/api.pdf), service firebase [tp6](./td_tp/tp6)

Binary file not shown.

BIN
R4.01_R4.A.10/cours/api.pdf Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,54 @@
## Thème
Écrire une application web en javascript qui permet de consulter les données de
parcours sup (vœux de poursuite d'études et de réorientation dans l'enseignement
supérieur et réponses des établissements) afin d'aider un(e) lycéén(e) à faire ses choix.
- La partie cliente devra être réaliser au moyen du framework [riotjs](https://riot.js.org/).
- Les données seront consommées au moyen de [l'api](https://data.enseignementsup-recherche.gouv.fr/explore/dataset/fr-esr-parcoursup/api/?timezone=Europe%2FBerlin&sort=tri) opendata. (cf [méthodologie](https://data.enseignementsup-recherche.gouv.fr/api/datasets/1.0/fr-esr-parcoursup/attachments/methodologie_opendata_2025pdf/))
- La localisation utilisera openstreet map et l'api [Leaflet](https://leafletjs.com/).
- Les graphiques seront réalisés au moyen de [chart css](https://chartscss.org/).
## Fonctionnalités
#### Recherche des formations par mots clés, avec localisation sur une carte.
[<a href="img/search.png">exemple</a>]
#### Vue d'une formation particulière, avec accès aux données de parcourssup, entre autres :
- les données lors de la phase d'admission,
- les données lors de la phase complémentaire,
- le profils des admis,
- l'évolution de la selectivité, des mentions au bac depuis 2020.
[<a href="img/formation.png">exemple</a>, <a href="img/profil.png">exemple</a>,
<a href="img/profil1.png">exemple</a>]
#### Aide au choix d'orientation
L'utilisateur doit pouvoir selectionner des formations/filières afin de les comparer et estimer
ses chances d'intégrations en fonction de la série de son bac et de sa moyenne en terminale.
[<a href="img/selection1.png">exemple</a>
, <a href="img/selection2.png">exemple</a>]
Les choix de l'utilisateur devront au moins être persistant localement. Vous pouvez, losque tout fonctionne,
mettre en oeuvre une persistance avec [firebase](https://firebase.com).
## Réalisation
1. Une partie de votre travail consiste à comprendre comment fonctionne l'api (entrées/sorties), et comment l'utiliser. N'hésitez pas à encapsuler/abstraire les informations de l'api dans votre propre modèle.
2. Le but est d'utiliser la programmation déclarative et par composants de RIOT.js. Il faut donc l'architecturer et l'organiser en
conséquence. En particulier, il faut profiter pleinement de l'utilisation de composants le plus génériques possibles.
3. Il faut utiliser des urls routables. Riot.js vient avec un [router](https://github.com/riot/route) très simple d'utilisation.
Je vous expliquerai comment mettre en oeuvre la réécriture d'url avec apache.
4. Il est possible d'utiliser le pattern observable, avec une bibliothèque adhoc ([exemple](https://github.com/riot/observable))
5. Dans le depot GIT de votre projet, il faut une description des composants, leurs entrées, leurs fonctions, et comment
ils communiquent avec le reste du monde.
## Attendus
Un mail (sujet S4WEB) m'indiquant les informations suivantes :
- l'url de votre projet sous la forme : http://dwarves.iut-fbleau.fr/~login/parcoursup
- l'url du dépôt GIT avec vos sources sur dwarves.iut-fbleau.fr
- les noms du binôme.
Le tout est à finaliser avant le Vendredi 03 avril 2025, 18 heures. Une soutenance aura lieu la semaine du 30/03.

View File

@@ -0,0 +1,17 @@
## Groupes projet
- Rayan Lankechari / Ibrahima Bah
- Demrici-Özmen Canpolat / Eliot Maxime
- Ozvann ABRAHAM / Karl FRAMERY
- SOLAR Dimitri / ZAABAY Tarehi
- Nicolas Miekisiak / Loïc Sainton
- Torreblanca Mathys / Poitou Enzo
- WIECZOREK Valentin / PLOUVIER Luka
- Kouami Kpeglo / Alexis Fort
- Ugo Faye / Mathis Leclere
- Nathan Couchot / Théo Anastasio / Adrien Rabot
- Pierre COURTEHOUX / Lukas SIMOES
- CAMILLE Cléo / Warrhen Roland
- Aylane Sehl / Séri-Khane / ??
- Arwa Ben Fraj / Bounni Loubelo Benicia
- Hicham Cherifi / Wael Atik
- DERQSI BILAL / CAMILLE LECHAVLIER

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -0,0 +1,84 @@
#### Ex1 : modele MVC et pattern strategy
> Stratégie est un patron de conception comportemental qui permet de définir une
> famille dalgorithmes, de les mettre dans des classes séparées et de rendre
> leurs objets interchangeables. (source wikipédia)
Le but est de réaliser ce pattern de conception dans le jeu très simple du chifoumi.
<div align="center">
<img src="./img/chifoumi.png">
</div>
Pour l'instant, le jeu utilise le pattern MVC. Le modèle, qui calcule le coup de l'ordinateur utilise
un tirage aléatoire. On veut pouvoir utilisé d'autres méthodes, qui utilisent l'historique des coups
joués par le joueur.
1. Modifiez le modèle et la vue pour que le jeu affiche le pourcentage de victoires, matchs nuls et défaites du joueur depuis le début
de la partie.
On veut maintenant séparer la façon dont l'ordinateur choisit son coup de la logique du jeu. Le modèle utilisera
une stratégie donnée.
2. Créez un sous-répétoires `stratégies` dans lequel on stokera les différentes stratégies disponibles.
Les différentes stratégies réaliseront l'interface
```js
getChoice(playerHistory)
```
qui calcule le coup de l'ordinateur, en fonction de l'historique des différents coups du joueur.
3. Ecrivez 3 stratégies simples `RandomStrategy.js` (stratégie initiale), `CopyPlayerStrategy.js`
(joue le même coup que le joueur) `CounterMostUsedStrategy.js` (joue le coup le plus joué par le joueur) :
Chaque fichier implémente la stratégie correspondante sous la forme :
```js
export default class RandomStrategy {
getChoice(playerHistory) {
....
}
}
```
4. Mettez à jour le modèle pour qu'il puisse utiliser une stratégie donnée.
5. testez dans le main.
#### Ajout d'une stratégie
On va ajouter une stratégie markovienne d'ordre 1. On fait
l'hyptohése que le coup du joueur dépend de son coup précedent (ordre 1).
On met à jour au fur et à mesure la matrice de transitions entre
les coups joué par le joueur. Par exemple,
```js
{
rock: { rock: 2, paper: 5, scissors: 1 },
paper: { rock: 1, paper: 3, scissors: 4 },
scissors: { rock: 6, paper: 1, scissors: 2 }
}
```
signifie qu'après paper, le joueur a joué 1 fois rock, 3 fois paper, et 4 fois scissors.
On se sert de la matrice pour contrer la prédiction.
5. Écrivezz cette stratégie, et testez la.
#### Stratégie mixte
Le but est d'implanter une stratégie mixte. On se donne une probabilité `p`.
- la stratégie markovienne est jouée avec la probabilité `p`.
- la stratégie aléatoire est jouée avec la probabilité `1-p`
Écrivez la stratégie mixte, et testez.
#### Stratégie adaptative
La probabilité `p` dépend du score. On l'adapte au fur et à mesure. Si on gagne beaucoup (trop),
on joue au hasard, sinon avec Markov.

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,41 @@
.game {
}
.choices{
display : flex;
align-items:stretch;
height:8em;
}
.choices > span:nth-child(2) {
margin-left:3em;
}
.choices span i{
font-size: 2em;
cursor: pointer;
border: none;
margin-right:0.25em;
transition: transform 0.2s, color 0.2s;
}
#player,#computer{
font-size: 3em;
border: none;
margin-right:0.25em;
}
.choices span i:hover {
color:#398712
}
#player {
color:#398712
}
#computer {
color:#D93526;
}

View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Pierre Feuille Ciseaux</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<main>
<h1>
Pierre - Feuille - Ciseaux
</h1>
<div class="choices">
<span>
<i data-choice="rock" class="far fa-hand-rock"></i>
<i data-choice="paper" class="far fa-hand-paper"></i>
<i data-choice="scissors" class="far fa-hand-scissors"></i>
</span>
<span>
<span id="player"></span>
<span id="computer"></span>
</span>
</div>
<div class="game">
<p id="score"></p>
<p id="result"></p>
</div>
</main>
<script type="module" src="js/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,18 @@
export default class GameController {
constructor(model, view) {
this.model = model;
this.view = view;
this.view.bindPlay(this.handlePlay);
this.view.displayScore(this.model.getScore());
}
handlePlay = (playerChoice) => {
const computerChoice = this.model.getComputerChoice();
const result = this.model.getResult(playerChoice, computerChoice);
this.view.displayResult(playerChoice, computerChoice, result);
this.view.displayScore(this.model.getScore());
}
}

View File

@@ -0,0 +1,9 @@
import GameModel from "./model.js";
import GameView from "./view.js";
import GameController from "./controller.js";
const app = new GameController(
new GameModel(),
new GameView()
);

View File

@@ -0,0 +1,29 @@
export default class GameModel {
constructor() {
this.choices = ["rock", "paper", "scissors"];
this.score = { player: 0, computer: 0};
}
getComputerChoice() {
const index = Math.floor(Math.random() * this.choices.length);
return this.choices[index];
}
getResult(player, computer) {
if (player === computer) return "égalité";
if (
(player === "rock" && computer === "scissors") ||
(player === "paper" && computer === "rock") ||
(player === "scissors" && computer === "paper")
) {
this.score.player++;
return "gagné";
}
this.score.computer++;
return "perdu";
}
getScore() {
return this.score;
}
}

View File

@@ -0,0 +1,50 @@
export default class GameView {
#icons = {
"rock" : "far fa-hand-rock",
"paper" : "far fa-hand-paper",
"scissors" : "far fa-hand-scissors"
}
constructor() {
this.resultEl = document.getElementById("result");
this.scoreEl = document.getElementById("score");
this.buttons = document.querySelectorAll(".choices span i");
this.player = document.getElementById("player");
this.computer = document.getElementById("computer");
}
bindPlay(handler) {
this.buttons.forEach(button => {
button.addEventListener("click", () => {
handler(button.dataset.choice);
});
});
}
displayResult(player, computer, result) {
let i = document.createElement("i");
i.classList.add(...this.#icons[player].split(' '))
this.player.replaceChildren(i)
i = document.createElement("i");
i.classList.add(...this.#icons[computer].split(' '))
this.computer.replaceChildren(i)
this.resultEl.innerHTML =
`Joueur <i class="${this.#icons[player]}"></i>, ordinateur <i class="${this.#icons[computer]}"></i> → ${result}`;
}
displayScore(score) {
let winRate = ((score.player * 100 / score.count) || 0).toFixed(2)
let lossRate = ((score.computer * 100 / score.count) ||0).toFixed(2)
let drawRate = (100 - winRate - lossRate).toFixed(2)
this.scoreEl.textContent =
`Score — Joueur: ${score.player} | Ordinateur: ${score.computer}`;
}
}

View File

@@ -0,0 +1,100 @@
# TP javascript : Ajax, promesses.
Vous disposez tous, à la racine de votre compte, d'un répertoire `public_html` qui est servi (http/https) par le serveur dwarves.
Pour accéder à vos pages, utilisez l'url :
> http(s)://dwarves.[arda|iut-fbleau.fr]/~login
Pour tester les différentes api http, vous pouvez utilisez la commande `curl`.
#### Ex1
Le but est de faire une recherche de film en utilisant l'api [OMDb](https://www.omdbapi.com/) (Open Movie Database).
![movie](img/search.png?style=centerme)
Son utilisation nécessite une clé. Vous pouvez utiliser la mienne `2fcb2848`. Si
la limite de requêtes est atteinte, générez votre propre clé.
Complétez le [code](./src/ex1).
- J'ai volontairement utilisé des modules. Il vous faut donc tester l'application avec
http.
- Écrire la fonction du modèle
```js
getMovies(search)
```
Cette fonction renvoie une promesse qui permet de faire une requête ajax vers l'api OMDb. Pour ajax,
utilisez d'abord l'interface `fetch`, ~~puis l'objet `XMLHttpRequest`~~.
- Écrire la fonction du contrôleur
```js
async search(searchMovie)
```
qui permet de faire une recherche. Cette fonction utilise évidemment la fonction précédente `getMovies`.
- Écrire la fonction de la vue
```js
renderList(movies)
```
qui construit la liste des films affichés. La structure attendue est
```html
<li>
<a href="http://www.imdb.com/title/tt0068646" target="_blank">The Godfather</a><span>1972</span>
</li>
```
#### Ex2
Le but, dans un premier temps, est d'écrire une interface, avec ajax, qui permette de jouer au jeu suivant :
- On a une grille dans laquelle sont cachés des renards (on en connait le nombre initial).
- A chaque tour, on choisit de tirer sur un case. On a l'alternative suivante :
- on tue un renard,
- on récupére les nombres de renards sur la grille sur la ligne, colonne et diagonales de la case.
<div align="center">
<img src="img/renard1.png">
</div>
Le jeu utilise un serveur http à l'url suivante
```
https://dwarves.iut-fbleau.fr/foxes/foxes.php
```
Voici les urls du jeu :
```
https://dwarves.iut-fbleau.fr/foxes/foxes.php?new&size=10&foxes=10
```
initialise la partie , avec la taille de la grille et le nombre de renards
dont la position est aléatoire (le script utilise des sessions de cinq minutes).
La réponse normale, en json :
```json
{"status":"ok","foxes":10,"tries":0}
```
```
https://dwarves.iut-fbleau.fr/foxes/foxes.php?X=1&Y=3
```
permet de tirer sur une case. Le serveur répond
```json
{"status":"ok","foxes":2,"tries":1}
```
`foxes` vaut -1 si le coup est gagnant, sinon donne le nombre de renards de la colonne, ligne et diagonales de la case.
En cas de victoire, le status est `win`. En cas d'erreur, le status est `nok`.
**Remarque**
Ajouter l'option `credentials` à vos requêtes pour utiliser la session en cours.

View File

@@ -0,0 +1,35 @@
#### XMLHttpRequest
```js
let xhr = new XMLHttpRequest()
xhr.open("GET","mon/url")
xhr.onload = ...
xhr.onerror = ...
xhr.send()
```
#### Promise
```js
let promise = new Promise ((resolve,reject) => {
setTimeout(() => {
resolve("OK")
},1000)
})
promise.then(data => ....)
```
#### async/await
```js
function getUser(email){
return new Promise(...)
}
async function updateUser(){
let user = await getUser(...)
console.log(user)
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

View File

@@ -0,0 +1,86 @@
main {
position: absolute;
top: 2rem;
left: 50%;
transform: translate(-50%, 0);
}
.loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: 6rem 0 0;
}
.error {
color: #FFFAAA;
margin: 1rem 0;
}
label {
align-items: center;
display: flex;
flex-direction: column;
font-size: 1.6rem;
}
label span {
text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
}
input {
margin: 1rem 0 0;
font-size: 1.6rem;
font-weight: 300;
padding: 0.8rem 1rem;
color: white;
border: 1px solid rgba(255, 255, 255, 0.05);
background: rgba(255, 255, 255, 0.05);
transition: all 0.3s;
box-shadow: 1px 1px 2px rgba(0,0,0, 0.3);
-moz-appearance:none;
-webkit-appearance:none;
outline: none;
}
input:focus {
border: 1px solid transparent;
background: rgba(255, 255, 255, 0.08);
}
ul {
padding: 0;
margin: 1rem 0 2rem;
}
ul li {
padding: 0.6rem 1rem;
margin: 1px 0;
line-height: 1.4rem;
display: flex;
justify-content: space-between;
align-items: center;
align-content: space-between;
text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
background: rgba(255, 255, 255, 0.08);
box-shadow: 0 0 2px rgba(0,0,0, 0.3);
box-sizing: border-box;
}
ul li:hover,
ul li:active,
ul li:focus {
background: rgba(255, 255, 255, 0.1);
}
ul li a {
margin: 0 0.6rem 0 0;
text-decoration: none;
color: white;
}
ul li span {
opacity: 0.5;
}
body {
margin: 0;
font-family: 'Helvetica Neue', Helvetica, Arial;
font-weight: 300;
background-size: cover;
background-attachment: fixed;
background-image: -webkit-radial-gradient(ellipse farthest-corner at top, #661141, #000000);
background-image: radial-gradient(ellipse farthest-corner at top, #661141, #000000);
color: white;
}

View File

@@ -0,0 +1,13 @@
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg width="44" height="44" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g fill="none" fill-rule="evenodd" stroke-width="2">
<circle cx="22" cy="22" r="1">
<animate attributeName="r" begin="0s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite"/>
<animate attributeName="stroke-opacity" begin="0s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite"/>
</circle>
<circle cx="22" cy="22" r="1">
<animate attributeName="r" begin="-0.9s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite"/>
<animate attributeName="stroke-opacity" begin="-0.9s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite"/>
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1,width=device-width">
<link rel="stylesheet" type="text/css" href="./css/style.css">
</head>
<body>
<!-- vue html -->
<main>
<label>
<span>Search a movie</span>
<input type="input" placeholder="28 Days Later..">
</label>
<div class="loader">
<img src="./img/puff.svg">
</div>
<p class="error"></p>
<div id="list-movies">
</div>
</main>
</body>
<script type="module" src="./module/app.js"></script>
</html>

View File

@@ -0,0 +1,7 @@
import model from '../module/model.js'
import Controller from '../module/controller.js'
import View from '../module/view.js'
const view = new View()
const app = new Controller(view,model)

View File

@@ -0,0 +1,26 @@
class Controller {
constructor(view,model){
this.view = view
this.model = model
this.loading = false
this.lastSearch = null
this.error = null
this.results = []
this.view.setLoading(false)
this.view.bindSearch(this.search.bind(this))
}
reset() {
this.loading = false
this.error = null
this.results = []
}
async search(searchMovie) {
// TODO
}
}
export default Controller

View File

@@ -0,0 +1,12 @@
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds.
function debounce(fn, wait) {
let timeout
return (...args) => {
clearTimeout(timeout)
timeout = setTimeout(() => fn(...args), wait)
}
}
export default debounce

View File

@@ -0,0 +1,9 @@
let apiKey = '2fcb2848'
let model = {
getMovies(search){
// TODO
}
}
export default model

View File

@@ -0,0 +1,44 @@
import debounce from "./helpers.js"
class View {
constructor(){
this.listMovies = document.querySelector("#list-movies")
this.inputSearch = document.querySelector("input")
this.loader = document.querySelector(".loader")
this.message = document.querySelector("p.error")
}
#getInput(){
return this.inputSearch.value
}
setLoading(loading){
if (loading)
this.loader.style.display = "block"
else
this.loader.style.display = "none"
}
renderMessage(error){
this.message.style.display = "block"
this.message.textContent = error
}
renderList(movies){
let ul = document.createElement("ul")
movies.forEach((movie)=>{
// TODO
})
this.listMovies.replaceChildren(ul)
}
bindSearch(handler){
this.inputSearch.addEventListener("input",debounce((e)=>{
handler(this.#getInput())
},500))
}
}
export default View

View File

@@ -0,0 +1,36 @@
import loader from './loader.js';
const board = document.querySelector("div.board");
const form = document.querySelector("form");
const message = document.querySelector("#message");
const ld = new loader(document.getElementById("loader"));
let url = 'https://dwarves.iut-fbleau.fr/foxes/foxes.php';
let foxes;
let size;
let newBoard = ( (size ) => {
let frag = document.createDocumentFragment();
for (let i = 0; i< size; i++){
let div = document.createElement("div");
for(let j = 0; j < size; j++){
let span = document.createElement("span");
span.dataset.num = size*i + j;
div.appendChild(span);
}
frag.appendChild(div);
}
board.replaceChildren(frag);
})
form.addEventListener("submit", (async (ev) => {
ev.preventDefault();
// TODO
}))
board.addEventListener("click", ( async (ev) => {
// TODO
}))

View File

@@ -0,0 +1,54 @@
article {
text-align : center;
}
.board > div {
display : flex;
}
article .board {
display : inline-block;
}
.board span {
display: inline-block;
vertical-align:baseline;
width: 50px;
height: 50px;
/*padding : 1em;*/
margin : 0.1em;
cursor: pointer;
border: 1px solid #444;
/*background: radial-gradient(rgb(150,250,150), #00ee00);*/
}
.board span:hover {
background: #3AB903;
background: radial-gradient(rgb(66, 255, 66), #065006);
}
.board span.on {
background: #009900;
}
div.is-loading {
position: fixed;
z-index: 999;
overflow: show;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
div.is-loading:after {
animation: spinAround 500ms infinite linear;
border: 2px solid hsl(0deg, 0%, 86%);
border-radius: 9999px;
border-right-color: transparent;
border-top-color: transparent;
content: "";
display: block;
position: relative;
top: calc(50% - 5em);
left: calc(50% - 5em);
width: 10em;
height: 10em;
border-width: 0.25em;
}

View File

@@ -0,0 +1,35 @@
<!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"
>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<main>
<div id="loader" ></div>
<hgroup>
<h4>Foxes</h4>
<p>Le but est de tuer tous les renards en minimisant le nombre de coups joués.</p>
</hgroup>
<p id="message"></p>
<article>
<div class="board">
</div>
</article>
<form>
<fieldset role="group">
<input type="text" name="size" placeholder="Size">
<input type="text" name="foxes" placeholder="Foxes">
<input type="submit" value="New Game">
</fieldset>
</form>
</main>
<script type="module" src="app.js"></script>
</body>
</html>

View File

@@ -0,0 +1,12 @@
class loader {
constructor(node){
this.node = node
}
set(loading){
if (loading)
this.node.classList.add("is-loading")
else
this.node.classList.remove("is-loading")
}
}
export default loader

View File

@@ -0,0 +1,39 @@
# TP javascript : riot.js
La [documentation](https://riot.js.org/) de riot.js
#### Ex1
Voici un [exemple](./src/ex1) d'application (todo list) écrite avec riot.js.
<div align="center">
<img src="./img/todo.png">
</div>
Le but est de comprendre le code pour prendre en main Riot.js
- Complétez la fonction `add` qui permet d'ajouter une tâche.
- Faites en sorte que le bouton `clear done` soit desactivé quand il n'y a pas de tâches accomplies.
- Complétez la fonction `clear` qui retire les tâches accomplies.
- Mettez en oeuvre les filtres `All`, `Active` et `Done`.
- Complétez le code qui permet de supprimer une tâche.
- Ajoutez le nombre de tâches restantes.
- Modifiez le code pour que les tâches soient stockées localement (utilisez l'objet `localStorage`).
#### Ex2
Voici un [exemple](./src/ex2) d'application (radar chart) écrite avec riot.js.
<div align="center">
<img src="./img/radar.png">
</div>
- Complétez les méthodes `add` et `remove`.
- Créez un nouveau composant `slider.riot`, qui vous utiliserez dans app.riot
#### Ex3
L'api DummyJSON permet de manipuler des données fictives. Ecrire, avec riotjs, une application qui permet :
- de récuperer depuis l'url `https://dummyjson.com/products` une liste de produits
- pour chaque produit, afficher le titre, prix et image.
- ajouter un filtre `prix < 100`, et un bouton `voir détails`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1,28 @@
<!doctype html>
<html>
<head>
<title>Riot todo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="todo.css">
<script src="todo.riot" type="riot"></script>
<script src="https://unpkg.com/riot@10.1.2/riot+compiler.min.js"></script>
</head>
<body>
<todo />
</body>
<script>
riot.compile().then(() => {
riot.mount('todo', {
title: 'I want to behave!',
todos: [
{ title: 'Avoid excessive caffeine', done: false ,id : 0},
{ title: 'Be less provocative', done: true , id:1},
{ title: 'Be nice to people', done: true, id:2}
]
})
})
</script>
</html>

View File

@@ -0,0 +1,112 @@
body {
font-family: 'myriad pro', sans-serif;
font-size: 20px;
border: 0;
}
todo {
display: block;
max-width: 500px;
margin: 5% auto;
}
form input {
font-size: 85%;
padding: .4em;
border: 1px solid #ccc;
border-radius: 2px;
}
button {
background-color: #1FADC5;
border: 1px solid rgba(0,0,0,.2);
font-size: 75%;
color: #fff;
padding: .4em 1.2em;
border-radius: 2em;
cursor: pointer;
margin: 0 .23em;
outline: none;
}
button[disabled] {
background-color: #ddd;
color: #aaa;
}
ul {
padding: 0;
}
li {
list-style-type: none;
padding: .2em 0;
position: relative;
}
.completed {
text-decoration: line-through;
color: #ccc;
}
label {
cursor: pointer;
}
.filters {
margin-top: 10px;
padding: 0;
list-style: none;
/* position: absolute;*/
right: 0;
left: 0;
}
.filters li {
display: inline;
}
.filters li a,.filters li span {
color: inherit;
/* margin: 3px;*/
margin-right:10px;
padding: 3px 7px;
text-decoration: none;
font-size : 0.75em;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
/* width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;*/
color: #cc9a9a;
/* margin-bottom: 11px;*/
transition: color 0.2s ease-out;
}
li .destroy:hover {
color: #af5b5e;
}
li .destroy:after {
content: '\274c';
}
li:hover .destroy {
display: block;
}

View File

@@ -0,0 +1,63 @@
<todo>
<h3>{ props.title }</h3>
<ul>
<li each={ todo in state.todos } key = {todo.id}>
<label class={ todo.done ? 'completed' : '' }>
<input
type="checkbox"
checked = { todo.done }
onclick = { () => toggle(todo) } />
{ todo.title }
</label>
<span class="destroy" onclick={() => remove(todo)}></span>
</li>
</ul>
<form onsubmit={ add }>
<input oninput={ edit } />
<button disabled={ !state.text }>
Add #{ state.todos.length + 1 }
</button>
<button onclick={ clear }>Clear done</button>
<ul class="filters">
<li><span>0 todos left</span> </li>
<li> <a href="#"> All</a></li>
<li> <a href="#">Active</a></li>
<li> <a href="#">Done</a></li>
</ul>
</form>
<script>
export default {
onBeforeMount(props, state) {
// initial state
this.state = {
todos: props.todos,
text: '',
}
},
edit(e) {
// update only the text state
this.update({
text: e.target.value
})
},
clear(e) {
// TODO
},
add(e) {
// TODO
},
toggle(todo) {
todo.done = !todo.done
this.update()
},
remove(todo){
// TODO
}
}
</script>
</todo>

View File

@@ -0,0 +1,18 @@
# Riot4 Radar Chart
## Usage
First of all, plz execute this commands.
```cmd
$ cd ../
$ yarn install
$ yarn radar
```
Perhaps the browser will open automatically and the application should start.
URL: [http://127.0.0.1:8080/](http://127.0.0.1:8080/)
## Demo
demo: [CodeSandbox](https://codesandbox.io/embed/riot4-template-0f6i0)

View File

@@ -0,0 +1,62 @@
<app>
<h2>{ props.title }</h2>
<div id="radar">
<!-- Use the component -->
<svg
is="polygraph"
stats={ state.stats } />
<!-- controls -->
<div>
<div each={ (stat, index) in state.stats }>
<label>{ stat.label }</label>
<input type="range"
onchange={ changeValue }
min="0"
max="100"
data-index={ index }
value={ stat.value }>
<span>{ stat.value }</span>
<button onclick={ remove } class="remove" value={ index }>X</button>
</div>
<!-- add item -->
<form id="add">
<input type="text"
name="newlabel"
value={ state.newLabel }
oninput={ inputStat }>
<button onclick={ add }>Add a Stat</button>
</form>
</div>
</div>
<script>
export default {
state: {
newLabel: '',
stats: []
},
onBeforeMount(props, state) {
state.stats = props.stats
},
add(e) {
// TODO
},
remove(stat) {
// TODO
},
inputStat(e) {
this.state.newLabel = e.target.value
},
changeValue(e) {
this.state.stats[e.target.dataset.index].value = e.target.value
this.update()
}
}
</script>
</app>

View File

@@ -0,0 +1,31 @@
<polygraph>
<g>
<polygon points={ points() }></polygon>
<circle cx="200" cy="200" r="160"></circle>
<text
each={ (stat, index) in state.stats }
index={ index }
stat={ stat }
total={ state.stats.length }
is="text" />
</g>
<script>
export default {
state: {
stats: []
},
onBeforeMount(props, state) {
state.stats = props.stats
},
// a computed property for the polygon's points
points() {
const total = this.state.stats.length
return this.state.stats.map((stat, i) => {
const point = valueToPoint(stat.value, i, total)
return point.x + ',' + point.y
}).join(' ')
}
}
</script>
</polygraph>

View File

@@ -0,0 +1,25 @@
<text x={ state.point.x } y={ state.point.y }>
{ props.stat.label }
<script>
export default {
state: {
point: ''
},
onBeforeMount(props, state) {
state.point = valueToPoint(
+props.stat.value + 10,
props.index,
props.total
)
},
onBeforeUpdate(props, state) {
state.point = valueToPoint(
+props.stat.value + 10,
props.index,
props.total
)
}
}
</script>
</text>

View File

@@ -0,0 +1,13 @@
const valueToPoint = (value, index, total) => {
const x = 0
const y = -value * 1.6
const angle = Math.PI * 2 / total * index
const cos = Math.cos(angle)
const sin = Math.sin(angle)
const tx = x * cos - y * sin + 200
const ty = x * sin + y * cos + 200
return {
x: tx,
y: ty
}
}

Some files were not shown because too many files have changed in this diff Show More