Beispiel:JS-WebStorage-TodoList.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0;" />
  <link rel="stylesheet" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css" />  
  <style>
main {
  display: grid;
  grid: "head head" auto
        "liste form" 1fr / 1fr auto;
  column-gap: 2em;
}

main > h2:first-of-type {
  grid-area: head;
}
#todo {
  grid-area: liste;
}
form {
  width: 15em;
  grid-area: form;
}

.todo-form button, label, input {
  width: 90%;
  padding: 0.2em;
  margin: 0.2em;
}  

input {
  width: 86%;
  margin-bottom: 2em;
}
  
ul.todo-list {
	margin-top: 0.5em;
	padding: 2px;
	list-style-type: none;
  background-color: #a9a9a9;
  border-radius: 0.25em;
}
ul.todo-list.empty::before { display: block; text-align: center; content: "Die Liste ist leer"; }
ul.todo-list li {
  margin: 0 0 2px 0;
}
ul.todo-list li button {
  padding: 0.5em;
  width: 100%;
  text-align: left;
  border:none;
}

ul.todo-list li:last-child {
  margin-bottom: 0;
}

ul.todo-list li:first-child button {
  border-radius: 0.25em 0.25em 0 0;
}
ul.todo-list li:last-child button {
  border-radius: 0 0 0.25em 0.25em;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
	todoListe(document.forms[0], document.querySelector(".todo-list"));
});

const defaultOptions = {
	entryClass: 'todo-entry',
	createClass: 'todo-create',
	clearClass: 'todo-clear',
	idPrefix: 'todoItem-',
	storageName: 'todoListe'
};

function todoListe(todoForm, domListe, options) {
	let configuration = Object.create(defaultOptions);
	for (let opt in options) {
		if (defaultOptions.hasOwnPropertyName(opt))
			configurations[opt] = options[opt];
	}

	if (!(todoForm instanceof HTMLFormElement) || !(isList(domListe)) )
		throw new Error("Eingabe-Form und Anzeigeliste fehlen");

	const entryField   = todoForm.querySelector(`input[type=text].${configuration.entryClass}`);
	const createButton = todoForm.querySelector(`button.${configuration.createClass}`);
	const clearButton  = todoForm.querySelector(`button.${configuration.clearClass}`);
	if (!entryField || !createButton || !clearButton)
		throw new Error("Eingabeformular der Todo-Liste inkorrekt oder unvollständig");

	todoForm.addEventListener("submit", todoHinzufügen);
	clearButton.addEventListener("click", todoListeLöschen);
	domListe.addEventListener("click", todoEntfernen);

	let todoListe;
	ladeTodoListe();
	todoListe.forEach(eintrag => todoInsDOM(eintrag));
	markiereLeereListe();
	entryField.focus();

	function isList(element) {
		return element && (element instanceof HTMLUListElement || element instanceof HTMLOListElement);
	}
  
	function todoHinzufügen(submitEvent) {
		submitEvent.preventDefault();

		const todo = erzeugeTodo(entryField.value.trim());
		if (!todo) {
			alert("Bitte geben Sie etwas ein!");
			return;  // Leerer Eintrag
		}
		if (todoListe.find(eintrag => eintrag.text == todo.text)) {
			alert("Das steht schon auf der Liste!");
			return;  // Duplikat
		}

		todoListe.push(todo);
		todoInsDOM(todo);
		markiereLeereListe();

		speichereTodoListe();
		entryField.value = '';
		entryField.focus();
	}

	function todoEntfernen(clickEvent) {
		const domItem = clickEvent.target.closest("li");
		if (!domItem.id.startsWith(configuration.idPrefix)) {
			alert("Das ist kein Todo-Eintrag!");
			return;
		}
		const todoId = parseInt(domItem.id.substring(configuration.idPrefix.length));
		domItem.remove();
		markiereLeereListe();

		todoListe = todoListe.filter(eintrag => eintrag.id != todoId);
		speichereTodoListe();
		entryField.focus();
	}

	function todoListeLöschen() {
		todoListe = [];
		domListe.innerHTML = "";
		markiereLeereListe();

		speichereTodoListe();
		entryField.focus();    
	}

	function ladeTodoListe() {
		let einträgeJson = localStorage.getItem(configuration.storageName);
		todoListe = einträgeJson ? JSON.parse(einträgeJson) : [];
	}

	function speichereTodoListe() {
		if (todoListe.length > 0)
			localStorage.setItem(configuration.storageName, JSON.stringify(todoListe));  	
		else
			localStorage.removeItem(configuration.storageName);
	}

	function markiereLeereListe() {
		domListe.classList.toggle("empty", todoListe.length == 0);
	}

	function erzeugeTodo(text) {
		return text ? { id: Date.now(), text } : null;
	}

	function todoInsDOM(eintrag) {
		const domItem = document.createElement("li");
		domItem.id = `${configuration.idPrefix}${eintrag.id}`;
		domItem.innerHTML = `<button type='button'>${eintrag.text}</button>`;
		domListe.appendChild(domItem);
	}
}
</script>  
  <title>Beispiel: localStorage</title>
</head>
 
<body>
  <h1>HTML5 localStorage</h1>
 
  <main>
    <h2>ToDo-Liste</h2>
    <form class="todo-form">
      <label for="eingabe">neues Projekt hinzufügen:</label>
  		<input id="eingabe" class="todo-entry" value="" type="text">
	  	<button class="todo-create" id="mehr">neuen Eintrag hinzufügen</button>
		  <button type="button"  class="todo-clear" id="loeschen">alle Einträge löschen </button>
	  </form>
    <section id="todo">
    <p>Klicken Sie auf die Einträge, um sie zu entfernen.</p>
  	<ul class="empty todo-list"></ul>
    </section>
  </main>
</body>
</html>