Web: Client 2

Web: Client 2


4.3 - Laboratoire

5.1 - Compléments

Template

Template - MDN

Voir le code source
html
copier
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
</head>

<style>
/* Make sure error message always takes up space
to avoid list going down when error appears,
also see inline style on .invalid-feedback div */

.is-invalid + .invalid-feedback {
visibility: visible !important;
}
</style>
<body>

<div class="bg-white">
<template id="item-template">
<li class="mt-4">
<span class="name"></span>
<button class="btn btn-danger">X</button>
</li>
</template>

<div class="container-fluid">
<h1 class="mt-2">Tasks</h1>

<form>
<div class="row g-2 mt-4">
<div class="col-12 col-sm">
<input type="text" name="name" class="form-control">
<div class="invalid-feedback" style="display: block; visibility: hidden;">
Name is required
</div>
</div>
<div class="col-12 col-sm-auto">
<button type="submit" class="btn btn-primary w-100">+</button>
</div>
</div>
</form>

<ul id="items"></ul>
</div>

<script>
const form = document.querySelector('form');
const list = document.querySelector('#items');

form.onsubmit = function(evt) {
evt.preventDefault();

if (form.name.value.trim() == '') {
form.name.classList.add('is-invalid');

const removeInvalid = () => form.name.classList.remove('is-invalid');

form.name.oninput = removeInvalid
form.name.onblur = removeInvalid

return
}

const template = document.querySelector('#item-template').content.cloneNode(true);
const item = template.querySelector('li');

const span = item.querySelector('span');
span.textContent = form.name.value;

const button = item.querySelector('button');
button.onclick = function() {
if (confirm(`Delete '${span.textContent}'?`)) {
item.remove();
}
}

list.appendChild(item);
form.name.value = '';
form.name.classList.remove('is-invalid');
}
</script>
</div>
</body>

Bootstrap

Bootstrap

UX Formulaire

Voir le code source
html
copier
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

<style>
/* Make sure error message always takes up space
to avoid list going down when error appears,
also see inline style on .invalid-feedback div */

.is-invalid + .invalid-feedback {
visibility: visible !important;
}
</style>
</head>
<body>
<div class="bg-white">
<template id="item-template">
<li class="mt-4">
<div class="inline-read flex-row align-items-center" style="display: flex; gap: 16px;">
<span class="name me-4"></span>
<button class="edit btn btn-outline-success">Form</button>
<button class="edit btn btn-outline-warning">Inline</button>
<button class="edit btn btn-outline-info">Toggle</button>
<button class="edit btn btn-outline-dark" data-bs-toggle="modal" data-bs-target="#dialog">Dialog</button>
</div>

<div class="inline-edit row me-0" style="display: none;">
<div class="col-12 col-sm">
<input type="text" class="inline form-control">
</div>
<div class="col-12 col-sm-auto d-flex flex-row-reverse flex-sm-row" style="gap: 16px;">
<button type="submit" class="save btn btn-success">!</button>
<button type="button" class="delete btn btn-outline-danger">X</button>
<button type="button" class="cancel btn btn-outline-secondary me-4 me-sm-0 ms-sm-4">-</button>
</div>
</div>
</li>
</template>

<div class="container-fluid">
<h1 class="mt-2">Tasks</h1>

<div class="toggle-read flex-column" style="display: flex;">
<form>
<div class="row g-2 mt-4">
<div class="col-12 col-sm">
<input type="text" name="name" class="form form-control">
<div class="invalid-feedback" style="display: block; visibility: hidden;">
Name is required
</div>
</div>
<div class="form-read col-12 col-sm-auto align-items-start">
<button type="submit" class="add btn btn-primary w-100">+</button>
</div>
<div class="form-edit col-12 col-sm-auto flex-row-reverse flex-sm-row align-items-start" style="gap: 16px; display: none;">
<button type="submit" class="save btn btn-success">!</button>
<button type="button" class="delete btn btn-outline-danger">X</button>
<button type="button" class="cancel btn btn-outline-secondary me-4 me-sm-0 ms-sm-4">-</button>
</div>
</div>
</form>

<ul id="items"></ul>
</div>

<div class="toggle-edit flex-column" style="display: none;">
<h2>Edit</h2>

<div class="row">
<div class="col">
<div class="form-floating mb-3">
<input type="text" class="toggle form-control" id="item">
<label for="item">Name</label>
</div>
</div>
</div>

<div class="row">
<div class="col">
<button class="cancel btn btn-outline-secondary">-</button>
</div>
<div class="col-auto">
<button class="delete btn btn-outline-danger">X</button>
<button class="save ms-4 btn btn-success">!</button>
</div>
</div>
</div>
</div>

<div id="dialog" class="modal" tabindex="-1">
<div class="modal-dialog modal-lg dialog-edit">
<div class="modal-content">

<div class="modal-header">
<h5 class="modal-title">Edit</h5>
<button type="button" class="cancel btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>

<div class="modal-body">
<div class="form-floating mb-3">
<input type="text" class="dialog form-control" id="item">
<label for="item">Name</label>
</div>
</div>

<div class="modal-footer justify-content-between">
<button class="delete btn btn-outline-danger">X</button>
<button class="save ms-4 btn btn-success">!</button>
</div>

</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

<script>
let dialog = new bootstrap.Modal('#dialog');

const form = document.querySelector('form');
const list = document.querySelector('#items');

form.onsubmit = function(evt) {
evt.preventDefault();

if (form.name.value.trim() == '') {
form.name.classList.add('is-invalid');

const removeInvalid = () => form.name.classList.remove('is-invalid');

form.name.oninput = removeInvalid
form.name.onblur = removeInvalid

return
}

const template = document.querySelector('#item-template').content.cloneNode(true);
const item = template.querySelector('li');

const span = item.querySelector('span');
span.textContent = form.name.value;

const editButtons = item.querySelectorAll('button.edit');

for(let button of editButtons) {
button.onclick = window[`${button.textContent.toLowerCase()}Edit`];
}

list.appendChild(item);
form.name.value = '';
form.name.classList.remove('is-invalid');
}

window.formEdit = function (evt) {
const container = document;
const type = 'form';

startEditing(evt.target, container, type);
}

window.inlineEdit = function (evt) {
const container = evt.target.parentElement.parentElement;
const type = 'inline';

startEditing(evt.target, container, type);
}

window.toggleEdit = function (evt) {
const container = document;
const type = 'toggle';

startEditing(evt.target, container, type);
}

window.dialogEdit = function (evt) {
const container = document;
const type = 'dialog';

startEditing(evt.target, container, type);
}

function startEditing(target, container, type) {
toggleEditing(container, type, true);

const nameSpan = target.parentElement.parentElement.querySelector('.name');
const input = container.querySelector(`input.${type}`);

input.value = nameSpan.textContent;

const cancel = function() {
toggleEditing(container, type, false);

input.value = '';
input.classList.remove('is-invalid');
}

container.querySelector(`.${type}-edit .cancel`).onclick = cancel;

container.querySelector(`.${type}-edit .save`).onclick = function(evt) {
evt.preventDefault();

if (input.value.trim() == '') {
input.classList.add('is-invalid');

return
}

nameSpan.textContent = input.value;

cancel();
}

container.querySelector(`.${type}-edit .delete`).onclick = function() {
if (confirm(`Delete ${nameSpan.textContent}?`)) {
nameSpan.parentElement.parentElement.remove();

cancel();
}
}
}

function toggleEditing(container, type, editing) {
container.querySelectorAll(`.${type}-read`).forEach( i => i.style.display = editing ? 'none' : 'flex');
container.querySelectorAll(`.${type}-edit`).forEach( i => i.style.display = editing ? 'flex' : 'none');

if (type == 'dialog') {
editing ? dialog.show() : dialog.hide();
}
}
</script>
</div>
</body>