thomas
This commit is contained in:
39
TP4/EX0/app.riot
Normal file
39
TP4/EX0/app.riot
Normal file
@@ -0,0 +1,39 @@
|
||||
<app>
|
||||
<h1>Personnages des Simpsons</h1>
|
||||
<div class="controls">
|
||||
<button onclick="{ () => sort('prenom') }">Trier par Prénom</button>
|
||||
<button onclick="{ () => sort('age') }">Trier par Âge</button>
|
||||
</div>
|
||||
|
||||
<my-list personnages="{ state.personnages }" onselect="{ selectCharacter }"></my-list>
|
||||
|
||||
<div if="{ state.selectedCharacter }" class="selected-char">
|
||||
<h3>Personnage sélectionné :</h3>
|
||||
<p><strong>Nom :</strong> { state.selectedCharacter.prenom } { state.selectedCharacter.nom }</p>
|
||||
<p><strong>Âge :</strong> { state.selectedCharacter.age !== null ? state.selectedCharacter.age : 'inconnu' }</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onMounted(props) {
|
||||
this.update({
|
||||
personnages: [...props.personnages],
|
||||
selectedCharacter: null
|
||||
});
|
||||
},
|
||||
|
||||
sort(key) {
|
||||
const sorted = [...this.state.personnages].sort((a, b) => {
|
||||
if (a[key] === null) return 1;
|
||||
if (b[key] === null) return -1;
|
||||
return a[key] > b[key] ? 1 : -1;
|
||||
});
|
||||
this.update({ personnages: sorted });
|
||||
},
|
||||
|
||||
selectCharacter(character) {
|
||||
this.update({ selectedCharacter: character });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</app>
|
||||
43
TP4/EX0/index.html
Normal file
43
TP4/EX0/index.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Les Simpson avec Riot.js</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/riot@6.0.1/riot.min.js"></script>
|
||||
<style>
|
||||
body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; }
|
||||
.controls { margin-bottom: 20px; }
|
||||
button { margin: 0 5px; padding: 8px 12px; cursor: pointer; }
|
||||
.selected-char { margin-top: 20px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<app></app>
|
||||
|
||||
<script type="module">
|
||||
import './my-list.riot';
|
||||
import './app.riot';
|
||||
|
||||
const personnages = [
|
||||
{"id":"1","nom":"Simpson","prenom":"Homer","age":"38"},
|
||||
{"id":"2","nom":"Simpson","prenom":"Marge","age":"34"},
|
||||
{"id":"3","nom":"Simpson","prenom":"Bart","age":"10"},
|
||||
{"id":"4","nom":"Simpson","prenom":"Lisa","age":"8"},
|
||||
{"id":"5","nom":"Simpson","prenom":"Maggie","age":"1"},
|
||||
{"id":"6","nom":"Flanders","prenom":"Ned","age":"60"},
|
||||
{"id":"7","nom":"Flanders","prenom":"Todd","age":"8"},
|
||||
{"id":"8","nom":"Flanders","prenom":"Rod","age":"10"},
|
||||
{"id":"9","nom":"Van Houten","prenom":"Kirk","age":null},
|
||||
{"id":"10","nom":"Van Houten","prenom":"Milhouse","age":null},
|
||||
{"id":"11","nom":"Van Houten","prenom":"Luann","age":null},
|
||||
{"id":"12","nom":"Muntz","prenom":"Nelson","age":null},
|
||||
{"id":"13","nom":"Muntz","prenom":"Véronica","age":null},
|
||||
{"id":"14","nom":"Muntz","prenom":"Thomas Jr","age":null},
|
||||
{"id":"15","nom":"Lovejoy","prenom":"Timothy","age":null},
|
||||
{"id":"16","nom":"Burns","prenom":"Charles","age":null}
|
||||
];
|
||||
|
||||
riot.mount('app', { personnages });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
22
TP4/EX0/my-list.riot
Normal file
22
TP4/EX0/my-list.riot
Normal file
@@ -0,0 +1,22 @@
|
||||
<my-list>
|
||||
<ul>
|
||||
<li each="{ char in props.personnages }" onclick="{ () => onSelect(char) }">
|
||||
{ char.prenom } { char.nom } ({ char.age !== null ? char.age : 'âge inconnu' })
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
ul { list-style: none; padding: 0; }
|
||||
li { padding: 10px; border-bottom: 1px solid #eee; cursor: pointer; }
|
||||
li:hover { background-color: #f0f0f0; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onSelect(character) {
|
||||
// Émet un événement 'select' vers le parent avec le personnage sélectionné
|
||||
this.parent.selectCharacter(character);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</my-list>
|
||||
21
TP4/EX1/index.html
Normal file
21
TP4/EX1/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Todo List avec Riot.js</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/riot@6.0.1/riot.min.js"></script>
|
||||
<style>
|
||||
body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; }
|
||||
.filters button { margin: 0 5px; }
|
||||
ul { list-style: none; padding: 0; }
|
||||
li { margin: 5px 0; display: flex; align-items: center; gap: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<todo-app></todo-app>
|
||||
<script type="module">
|
||||
import './todo-app.riot';
|
||||
riot.mount('todo-app');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
96
TP4/EX1/todo-app.riot
Normal file
96
TP4/EX1/todo-app.riot
Normal file
@@ -0,0 +1,96 @@
|
||||
<todo-app>
|
||||
<h1>Ma Todo List</h1>
|
||||
<form onsubmit="{ addTodo }">
|
||||
<input type="text" placeholder="Ajouter une tâche..." value="{ state.newTodoText }">
|
||||
<button type="submit">Ajouter</button>
|
||||
</form>
|
||||
|
||||
<div class="filters">
|
||||
<button onclick="{ () => filter('all') }">Toutes ({ state.todos.length })</button>
|
||||
<button onclick="{ () => filter('active') }">Actives ({ state.activeTodosCount })</button>
|
||||
<button onclick="{ () => filter('done') }">Terminées ({ state.doneTodosCount })</button>
|
||||
<button onclick="{ clearDone }" disabled="{ state.doneTodosCount === 0 }">
|
||||
Effacer les terminées
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li each="{ todo in state.filteredTodos }" class="{ done: todo.done }">
|
||||
<input type="checkbox" checked="{ todo.done }" onchange="{ () => toggleTodo(todo.id) }">
|
||||
<span ondblclick="{ () => editTodo(todo.id) }">{ todo.text }</span>
|
||||
<button onclick="{ () => deleteTodo(todo.id) }">X</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.done { text-decoration: line-through; color: #999; }
|
||||
button[disabled] { cursor: not-allowed; opacity: 0.5; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onMounted() {
|
||||
this.loadTodos();
|
||||
},
|
||||
|
||||
loadTodos() {
|
||||
const savedTodos = localStorage.getItem('todos');
|
||||
this.update({ todos: savedTodos ? JSON.parse(savedTodos) : [], filter: 'all' });
|
||||
this.updateCounts();
|
||||
},
|
||||
|
||||
saveTodos() {
|
||||
localStorage.setItem('todos', JSON.stringify(this.state.todos));
|
||||
this.updateCounts();
|
||||
},
|
||||
|
||||
updateCounts() {
|
||||
const activeTodosCount = this.state.todos.filter(t => !t.done).length;
|
||||
const doneTodosCount = this.state.todos.filter(t => t.done).length;
|
||||
this.update({ activeTodosCount, doneTodosCount, filteredTodos: this.getFilteredTodos() });
|
||||
},
|
||||
|
||||
getFilteredTodos() {
|
||||
if (this.state.filter === 'active') {
|
||||
return this.state.todos.filter(todo => !todo.done);
|
||||
} else if (this.state.filter === 'done') {
|
||||
return this.state.todos.filter(todo => todo.done);
|
||||
}
|
||||
return this.state.todos;
|
||||
},
|
||||
|
||||
addTodo(e) {
|
||||
e.preventDefault();
|
||||
const text = this.state.newTodoText.trim();
|
||||
if (text) {
|
||||
const newTodo = { id: Date.now(), text, done: false };
|
||||
this.update({ todos: [...this.state.todos, newTodo], newTodoText: '' });
|
||||
this.saveTodos();
|
||||
}
|
||||
},
|
||||
|
||||
deleteTodo(id) {
|
||||
this.update({ todos: this.state.todos.filter(t => t.id !== id) });
|
||||
this.saveTodos();
|
||||
},
|
||||
|
||||
toggleTodo(id) {
|
||||
const updatedTodos = this.state.todos.map(t =>
|
||||
t.id === id ? { ...t, done: !t.done } : t
|
||||
);
|
||||
this.update({ todos: updatedTodos });
|
||||
this.saveTodos();
|
||||
},
|
||||
|
||||
clearDone() {
|
||||
this.update({ todos: this.state.todos.filter(t => !t.done) });
|
||||
this.saveTodos();
|
||||
},
|
||||
|
||||
filter(type) {
|
||||
this.update({ filter: type });
|
||||
this.updateCounts();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</todo-app>
|
||||
21
TP4/EX2/index.html
Normal file
21
TP4/EX2/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Recherche de films Riot.js</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/riot@6.0.1/riot.min.js"></script>
|
||||
<style>
|
||||
body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; }
|
||||
#movie-list { display: flex; flex-wrap: wrap; gap: 20px; justify-content: center; }
|
||||
.movie-card { width: 200px; border: 1px solid #ccc; padding: 10px; text-align: center; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||
.movie-card img { max-width: 100%; height: auto; border-radius: 5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<search-app></search-app>
|
||||
<script type="module">
|
||||
import './search-app.riot';
|
||||
riot.mount('search-app');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
34
TP4/EX2/search-app.riot
Normal file
34
TP4/EX2/search-app.riot
Normal file
@@ -0,0 +1,34 @@
|
||||
<search-app>
|
||||
<h1>Recherche de films</h1>
|
||||
<div class="search-container">
|
||||
<input type="text" placeholder="Titre du film..." oninput="{ handleInput }">
|
||||
<button onclick="{ searchMovies }">Rechercher</button>
|
||||
</div>
|
||||
|
||||
<div id="movie-list">
|
||||
<div each="{ movie in state.movies }" class="movie-card">
|
||||
<h3>{ movie.Title } ({ movie.Year })</h3>
|
||||
<img src="{ movie.Poster !== 'N/A' ? movie.Poster : 'https://via.placeholder.com/200x300.png?text=Pas+d%27image' }" alt="{ movie.Title }">
|
||||
</div>
|
||||
<p if="{ !state.movies.length && state.searched }">Aucun film trouvé.</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { getMovies } from './service.js';
|
||||
|
||||
export default {
|
||||
onMounted() {
|
||||
this.update({ movies: [], searched: false, searchTerm: '' });
|
||||
},
|
||||
|
||||
handleInput(e) {
|
||||
this.update({ searchTerm: e.target.value });
|
||||
},
|
||||
|
||||
async searchMovies() {
|
||||
const movies = await getMovies(this.state.searchTerm);
|
||||
this.update({ movies, searched: true });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</search-app>
|
||||
13
TP4/EX2/service.js
Normal file
13
TP4/EX2/service.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export const getMovies = async (search) => {
|
||||
const apiKey = '2fcb2848';
|
||||
const url = `https://www.omdbapi.com/?apikey=${apiKey}&s=${encodeURIComponent(search)}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
return data.Search || [];
|
||||
} catch (error) {
|
||||
console.error("Erreur lors de la recherche de films:", error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
24
TP4/EX3/index.html
Normal file
24
TP4/EX3/index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Todo List avec Router</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/riot@6.0.1/riot.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/riot-route@4.0.0/dist/route.min.js"></script>
|
||||
<style>
|
||||
body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; }
|
||||
.filters a { margin: 0 5px; padding: 5px 10px; border: 1px solid #ccc; text-decoration: none; color: #333; }
|
||||
.filters a.active { background-color: #eee; }
|
||||
.done { text-decoration: line-through; color: #999; }
|
||||
ul { list-style: none; padding: 0; }
|
||||
li { margin: 5px 0; display: flex; align-items: center; gap: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<todo-router></todo-router>
|
||||
<script type="module">
|
||||
import './todo-router.riot';
|
||||
riot.mount('todo-router');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
98
TP4/EX3/todo-router.riot
Normal file
98
TP4/EX3/todo-router.riot
Normal file
@@ -0,0 +1,98 @@
|
||||
<todo-router>
|
||||
<h1>Ma Todo List</h1>
|
||||
<form onsubmit="{ addTodo }">
|
||||
<input type="text" placeholder="Ajouter une tâche..." value="{ state.newTodoText }">
|
||||
<button type="submit">Ajouter</button>
|
||||
</form>
|
||||
|
||||
<div class="filters">
|
||||
<a href="#/all" class="{ active: state.filter === 'all' }">Toutes ({ state.todos.length })</a>
|
||||
<a href="#/active" class="{ active: state.filter === 'active' }">Actives ({ state.activeTodosCount })</a>
|
||||
<a href="#/done" class="{ active: state.filter === 'done' }">Terminées ({ state.doneTodosCount })</a>
|
||||
<button onclick="{ clearDone }" disabled="{ state.doneTodosCount === 0 }">
|
||||
Effacer les terminées
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li each="{ todo in state.filteredTodos }" class="{ done: todo.done }">
|
||||
<input type="checkbox" checked="{ todo.done }" onchange="{ () => toggleTodo(todo.id) }">
|
||||
<span ondblclick="{ () => editTodo(todo.id) }">{ todo.text }</span>
|
||||
<button onclick="{ () => deleteTodo(todo.id) }">X</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.done { text-decoration: line-through; color: #999; }
|
||||
button[disabled] { cursor: not-allowed; opacity: 0.5; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import * as route from 'riot-route';
|
||||
|
||||
export default {
|
||||
onMounted() {
|
||||
this.loadTodos();
|
||||
route.start(true);
|
||||
route.on('route', (collection, id, action) => {
|
||||
this.update({ filter: collection || 'all' });
|
||||
this.updateCounts();
|
||||
});
|
||||
},
|
||||
|
||||
loadTodos() {
|
||||
const savedTodos = localStorage.getItem('todos');
|
||||
this.update({ todos: savedTodos ? JSON.parse(savedTodos) : [], filter: route.current[0] || 'all' });
|
||||
this.updateCounts();
|
||||
},
|
||||
|
||||
saveTodos() {
|
||||
localStorage.setItem('todos', JSON.stringify(this.state.todos));
|
||||
this.updateCounts();
|
||||
},
|
||||
|
||||
updateCounts() {
|
||||
const activeTodosCount = this.state.todos.filter(t => !t.done).length;
|
||||
const doneTodosCount = this.state.todos.filter(t => t.done).length;
|
||||
this.update({ activeTodosCount, doneTodosCount, filteredTodos: this.getFilteredTodos() });
|
||||
},
|
||||
|
||||
getFilteredTodos() {
|
||||
if (this.state.filter === 'active') {
|
||||
return this.state.todos.filter(todo => !todo.done);
|
||||
} else if (this.state.filter === 'done') {
|
||||
return this.state.todos.filter(todo => todo.done);
|
||||
}
|
||||
return this.state.todos;
|
||||
},
|
||||
|
||||
addTodo(e) {
|
||||
e.preventDefault();
|
||||
const text = this.state.newTodoText.trim();
|
||||
if (text) {
|
||||
const newTodo = { id: Date.now(), text, done: false };
|
||||
this.update({ todos: [...this.state.todos, newTodo], newTodoText: '' });
|
||||
this.saveTodos();
|
||||
}
|
||||
},
|
||||
|
||||
deleteTodo(id) {
|
||||
this.update({ todos: this.state.todos.filter(t => t.id !== id) });
|
||||
this.saveTodos();
|
||||
},
|
||||
|
||||
toggleTodo(id) {
|
||||
const updatedTodos = this.state.todos.map(t =>
|
||||
t.id === id ? { ...t, done: !t.done } : t
|
||||
);
|
||||
this.update({ todos: updatedTodos });
|
||||
this.saveTodos();
|
||||
},
|
||||
|
||||
clearDone() {
|
||||
this.update({ todos: this.state.todos.filter(t => !t.done) });
|
||||
this.saveTodos();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</todo-router>
|
||||
Reference in New Issue
Block a user