Voir le code source
<!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>
<!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>
Voir le code source
<!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>
<!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>