todo riot, avec router

This commit is contained in:
2026-03-16 14:22:17 +01:00
parent 0490924e3d
commit a472e34bbe
9 changed files with 261 additions and 3 deletions

View File

@@ -105,6 +105,5 @@ Le modèle utilise PDO, en php. Il vous faudra créér une table avec les attrib
1. Complétez le fichier index.php
2. Testez votre api à la ligne de commandes en utilisant `curl`.
3. Connectez votre application todolist avec l'api.
Écrivez un module "abstrait" en javascript pour l'interaction
avec l'api. Ce module devra pouvoir être changer pour utiliser firebase **sans que l'application cliente ne change**.
4. Connectez votre api à l'application [todo](./src/todo-riot). Il faut
complétez le fichier api.js. Prenez soin de modifier le fichier `htaccess`.

View File

@@ -0,0 +1,74 @@
<app>
<router base = {base}>
<route path="/:filter?"
on-before-mount = { changeFilter }
on-before-update = { changeFilter }
>
<h1>To Do List</h1>
<todo-form
add = { add } />
<todo-nav
selection = {state.filter}
left = {this.state.todos.filter(todo => !todo.done).length} />
<todo-list
todos = { filterTodos() }
toggle = { toggle }
remove = { remove } />
</route>
</router>
<script>
export default {
base : '/~denis/web_2024/tp5/todo-riot/', // Votre URL
state : {
todos : [],
filter : 'all'
},
changeFilter(r){
this.state.filter = r.params.filter || 'all'
},
async onBeforeMount(props, state) {
let todos = await this.serviceData.getTodos()
this.state.todos = todos;
this.update()
},
filterTodos(){
if (this.state.filter === 'all')
return this.state.todos
if (this.state.filter === 'active')
return this.state.todos.filter(e=> !e.done)
if (this.state.filter === 'done')
return this.state.todos.filter(e=> e.done)
},
async remove(e,todo){
e.preventDefault()
let res = await this.serviceData.removeTodo(todo)
let todos = await this.serviceData.getTodos()
this.state.todos = todos
this.update()
},
async add(text) {
let res = await this.serviceData.addTodo({title : text , done : false})
let todos = await this.serviceData.getTodos()
this.state.todos = todos
this.update()
},
async toggle(todo) {
let res = await this.serviceData.toggleTodo(todo);
let todos = await this.serviceData.getTodos()
this.state.todos = todos
this.update()
}
}
</script>
</app>

View File

@@ -0,0 +1,16 @@
p.todo {
display : flex;
justify-content : space-between;
}
.done {
text-decoration: line-through;
color: #ccc;
}
.is-active {
color : #8EB901;
}
.delete {
background-color :#9B2318;
}

View File

@@ -0,0 +1,8 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /~denis/web_2024/tp5/todo-riot/ # votre url
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html [L]
</IfModule>

View File

@@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<title>Riot todo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<base href="/~denis/web_2024/tp5/todo-riot/">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdn.jsdelivr.net/npm/riot@10.0.0/riot+compiler.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@riotjs/route@10.0.0/index.umd.js"></script>
<link rel="stylesheet" href="css/todo.css">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
>
<!-- composants riot -->
<script src="app.riot" type="riot"></script>
<script src="todo-list.riot" type="riot"></script>
<script src="todo-nav.riot" type="riot"></script>
<script src="todo-form.riot" type="riot"></script>
</head>
<body>
<main class="container">
<app />
</main>
<script type="module">
import makeDataService from "./js/api.js";
riot.register('router', route.Router);
riot.register('route', route.Route);
riot.compile().then(async () => {
let sa = makeDataService();
riot.install(function(component){
if (component.name === "app")
component.serviceData = sa;
})
riot.mount('app')
})
</script>
</body>
</html>

View File

@@ -0,0 +1,45 @@
export default function makeDataService(){
let url = 'http://localhost/~denis/web_2024/tp5/api_php/todo/'
let service = {
getTodos : getTodos,
addTodo : addTodo,
removeTodo : removeTodo,
toggleTodo : toggleTodo,
};
async function getTodos()
{
let res = await fetch(url,{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
;
let json = await res.json();
return json.results;
}
async function addTodo(todo)
{
const response = await fetch(url, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify(todo)
});
}
async function removeTodo(todo)
{
// TODO
}
async function toggleTodo(todo)
{
// TODO
}
return service;
}

View File

@@ -0,0 +1,31 @@
<todo-form>
<form onsubmit = { add }>
<fieldset role="group">
<input type="text" placeholder="Buy milk and eggs..." oninput = { edit }>
<button disabled = { !state.text } ><i class="fas fa-plus"></i></button>
</fieldset>
</form>
<script>
export default {
state : {
text:''
},
edit(e) {
// update only the text state
this.state.text = e.target.value
this.update()
},
add(e) {
e.preventDefault()
this.props.add(this.state.text);
},
clear(e){
e.preventDefault();
this.props.clear()
}
}
</script>
</todo-form>

View File

@@ -0,0 +1,17 @@
<todo-list>
<article>
<div each={ todo in props.todos } key={todo.id}>
<p class="todo">
<label class={ todo.done ? 'completed' : null }>
<input
type="checkbox"
checked={ todo.done }
onclick={ () => props.toggle(todo) } />
<span class = {todo.done ? 'done':''}> { todo.title } </span>
</label>
<a href="#" onclick={(e)=>props.remove(e,todo)}><i class="fa-solid fa-trash"></i></a>
</p>
<hr>
</div>
</article>
</todo-list>

View File

@@ -0,0 +1,12 @@
<todo-nav>
<nav>
<ul>
<li><a class={props.selection === 'active'?'is-active':null} href="active"><i class="far fa-circle"></i></a></li>
<li><a class={props.selection === 'done'?'is-active':null} href="done"><i class="fas fa-circle"></i></a></li>
<li><a class={props.selection === 'all'?'is-active':null} href="all"><i class="fas fa-adjust"></i></a></li>
</ul>
<ul>
<li>{props.left} todos left</li>
</ul>
</nav>
</todo-nav>