Skip to content

Instantly share code, notes, and snippets.

@AndreasLonn
Created October 12, 2021 14:53
Show Gist options
  • Save AndreasLonn/513e4432f7b502b8cbf897cd123e7ee8 to your computer and use it in GitHub Desktop.
Save AndreasLonn/513e4432f7b502b8cbf897cd123e7ee8 to your computer and use it in GitHub Desktop.
A serverless HTML checklist that is run locally. Checked items are stored in localstorage in the web browser
<!--
This is a serverless checklist that is run locally. Checked items are
stored in localstorage in the web browser.
The content is stored as a javascript array for quick interpretation.
The indentation of the array is ignored. The number first number in the
array in the list array represents the indentation, while the string
is the text to be displayed. The strings are NOT escaped, so the strings
can contain HTML elements like links.
-->
<!DOCTYPE html>
<html lang="sv">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- English: Checklist -->
<title>Checklista</title>
<style>
html {
font-family: Arial, Helvetica, sans-serif;
}
body {
margin: 0;
}
button {
position: fixed;
top: 20px;
right: 20px;
padding: 5px 10px;
}
ol {
display: flex;
flex-direction: column;
padding: 0;
}
ol li {
display: grid;
grid-template-columns: max-content auto;
padding: 0;
}
ol li:nth-child(2n) {
background-color: #ddd;
}
ol li.checked {
background-color: #0f06;
}
input[type="checkbox"] {
width: 20px;
height: 100%;
margin: 0;
}
label {
padding: 10px;
font-size: 20px;
}
@media (min-width: 1000px) {
body {
padding: 0 40px 40px 40px;
}
button {
right: 40px;
}
}
</style>
</head>
<body>
<!-- English: Checklist -->
<h1>Checklista</h1>
<!-- English: Clear -->
<button id="clear">Rensa</button>
<ol id="checklist">
</ol>
<!-- The data file -->
<script src="data.js"></script>
<script>
/**
* Short for document.querySelector
*/
function $(elem) {
return document.querySelector(elem);
}
// Set the title to the one supplied in data.js
document.title = titel;
$("h1").innerText = titel;
var checklist = $("#checklist");
var localstorage = window.localStorage;
// Listen to checkboxes
checklist.addEventListener("input", event => {
// Make sure that the event is about checkboxes by
// checking that the ID start with "checkbox"
if(event.target.id.indexOf("checkbox") != 0) return;
// Update localstorage
localstorage.setItem(event.target.id, event.target.checked);
// Add or remove the "checked" class to the entire element
event.target.checked ?
event.target.parentElement.classList.add("checked") :
event.target.parentElement.classList.remove("checked");
// Update the list children (not HTML children) when a parent element is updated.
let children = checklist.children;
// Start at the checked element and go through all elements while the indentation
// is less than the originally checked element
for(let i = event.target.id.substr(9) - 1 + 2;
(i < children.length &&
children[i].getAttribute("data-i") >
event.target.parentElement.getAttribute("data-i")); i++) {
// Add or remove the "checked" class to the entire element
event.target.checked ?
children[i].classList.add("checked") :
children[i].classList.remove("checked");
// Check or uncheck the checkbox
children[i].firstChild.checked = event.target.checked;
// Update localstorage
localstorage.setItem(children[i].firstChild.id, event.target.checked);
}
});
// Handle clicks on the clear button
$("#clear").addEventListener("click", () => {
// English: "Do you really want to clear the checkmarks? (The list itself won't be affected)"
if(confirm("Vill du verkligen rensa kryssen? (Själva punkterna finns kvar)")) {
// Clear localstorage and reload the page
localstorage.clear();
location.reload();
}
});
// Go through the array in data.js
list.forEach((element, i) => {
// Create the element
let newElement = document.createElement("li");
// Read from localstorage
let checked = localstorage.getItem('checkbox_' + i) == "true";
// Check the checkbox if localstorage says so
if(checked) newElement.classList.add("checked");
// Set the indentation
newElement.setAttribute("data-i", element[0]);
// Fill the element with a checkbox and label
// As said at the top of the file, the list can contain HTML elements,
// so be careful what you put there, and ONLY use trusted data.js files
newElement.innerHTML =
`<input type="checkbox" ${checked ? "checked " : ""}id="checkbox_${i}" style="margin-left: ${element[0] * 50 + 10}px" />
<label for="checkbox_${i}">${element[1]}</label>`;
// Add the element to the list
checklist.appendChild(newElement);
});
</script>
</body>
</html>
var titel = "Checklist";
var list = [
[0, "This is a sample data.js file"],
[0, "You can have indentation:"],
[1, "This is level one indentation"],
[2, "This is level 2"],
[3, "This is level 3"],
[5, "This is level 5"],
[0, "You have to \"escape\" some characters like \" and \\. This is done by putting a \\ in front: \\\" and \\\\"],
[0, "If you check me, my children will be checked as well"],
[1, "Hello! I'm a child"],
[2, "Hello! I'm another child"],
[0, "You can also put HTML elements inside the list elements <a href=\"\" onclick=\"alert('Hello!')\">like this link that displays an alert dialog when clicked</a>"],
[0, "You can do a lot with links, like email addresses <a href=\"mailto:[email protected]?subject=You can even set the subject!&body=And the body!\">Click here to open the email app!</a>"]
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment