Here is the official demo of TodoList. You can run it live here :
TodoList.
Try it on your phone, and see how fast it is.
Features : multilines fields and localstorage.
<html lang="de">
<head>
<meta charset="utf-8">
<title>title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://efpage.de/DML/DML_homepage/lib/DML-min.js"></script>
</head>
<body>
<script>
let todos = []; // List of todos
const _w = "width: 100%; max-width: 450px;"
const _ba = _top+"min-height: 22px; width: 100%; border: none; resize: none; background-color: rgba(0,0,0,0); font-size: 20px; font-family: sans-serif;"
/*------------------------------------------------------
count active todos
------------------------------------------------------*/
function countTodos() {
let _active = 0;
todos.forEach(function (todo) {if (!todo.cb.checked) _active++;})
activecount.textContent = "Active: " + _active;
count.textContent = "Total: " + todos.length
}
/*------------------------------------------------------
save data
------------------------------------------------------*/
function saveData() {
localStorage.setItem("todocount", todos.length)
todos.forEach(function (todo, i) {
localStorage.setItem("todo" + i, todo.ta.value)
localStorage.setItem("state" + i, todo.cb.checked)
})
countTodos()
}
/*------------------------------------------------------
read old data
------------------------------------------------------*/
function readData(area) {
let n = localStorage.getItem("todocount");
for (let i = 0; i < n; i++) {
let content = localStorage.getItem("todo" + i);
if (content)
if (content.trim() != "") {
let todo = new todoObj(area, content);
todo.cb.checked = (localStorage.getItem("state" + i) != "false")
todo.ta.style.height = todo.ta.scrollHeight + "px";
todo.setState();
}
}
countTodos()
}
/*------------------------------------------------------
Make new todo Element and clear input
get workarea and textarea with content (will be cleared)
------------------------------------------------------*/
function mknew(workarea, ta) {
if (ta.value != "") {
new todoObj(workarea, ta.value);
ta.value = '';
ta.autosize()
}
saveData()
countTodos()
}
/****************************************************************************************
Class "todo" creates a new todo in area
****************************************************************************************/
class todoObj {
constructor(area, content) {
todos.push(this); // Add Element to todo array
selectBase(area); // start inside area
// Create a todo box
this.todo = selectBase(div("", "display: flex; position: relative; border-top: solid; border-width: 1px; "))
this.cb = checkbox("", "flex: 0 0 30px;align-self: center;");
this.ta = expandableTextarea(content, _ba); // Create input area
// Invisible Delete-Button to remove element
this.bt = button("x", "height: 28px; opacity: 0.0; transition: opacity 0.5s; "
+ " position: absolute; right: 10px; " + _top + _shadow);
this.bt.onclick = this.delete.bind(this)
// Set event functions
this.ta.addEventListener("blur", saveData); // Save data on exit
this.cb.onclick = () => { this.setState(); saveData(); } // Save data on state change
this.todo.onmouseenter = () => { this.bt.style.opacity = 1 }
this.todo.onmouseleave = () => { this.bt.style.opacity = 0 }
// run once to show state
this.setState();
unselectBase(2)
}
// Class funcitons:
/*------------------------------------------------------
set state color of the input area
------------------------------------------------------*/
setState() {
this.ta.style.backgroundColor = (this.cb.checked ? "#f0f0e0" : "#ffe");
this.ta.style.textDecoration = (this.cb.checked ? "line-through" : "none");
}
/*------------------------------------------------------
Delete todo Object
------------------------------------------------------*/
delete() {
todos = todos.filter(todo => todo != this) // Delete this element from list
this.todo.remove(); delete (this)
saveData();
}
} // end todo class
/****************************************************************************************
Create page content
****************************************************************************************/
div(h1("todos", "Text-align: center; text-shadow: 2px 2px 4px #444;" + _red), _w);
selectBase(div("", _w + " background-color: #ffe; " + _border + _radius + _bigPadding + _shadow));
// Top Input field
let ta = expandableTextarea("", { "placeholder": "What to do ?", "style":_ba})
// Area for Todos
let workarea = div();
// footer
hr("margin: 3px auto;")
selectBase(div("", "display: flex; justify-content: space-between; font-size: 80%;"))
let count = span("count");
let activecount = span("activecount");
unselectBase(2)
/****************************************************************************************
Events to create new todos
****************************************************************************************/
// Create new Todos on Return or exit
ta.onkeypress = (event) => {
if (event.which == 13) {
event.preventDefault(); // Remove CR from input
mknew(workarea, ta)
}
}
ta.onblur = () => { mknew(workarea, ta) }
readData(workarea)
/****************************************************************************************
save Data before unload
****************************************************************************************/
window.onbeforeunload = saveData;
</script>
</body>
</html>
Top comments (0)