import { englishPage } from "./language"
const KVSPACE = "todo_list";
const IPHEADER = "cdn-src-ip";
const defaultData = { todos: [] };
async function setCache(key, data) {
const kv = new EdgeKV({namespace: KVSPACE});
return await kv.put(key, data, {expiration: Math.floor(new Date().getTime()/1000)+60*60*24*29});
}
async function getCache(key) {
const kv = new EdgeKV({namespace: KVSPACE});
return await kv.get(key);
}
async function getTodos(request) {
const ip = request.headers.get(IPHEADER);
const myKey = `data-${ip}`;
let data;
const cache = await getCache(myKey);
if (!cache) {
await setCache(myKey, JSON.stringify(defaultData));
data = defaultData;
} else {
data = JSON.parse(cache);
}
const htmlFunc = englishPage(request) ? html_en : html
const body = htmlFunc(JSON.stringify(data.todos || []).replace(/</g, '\\u003c')).replace('client-ip', ip);
return new Response(body, {
headers: { 'Content-Type': 'text/html; charset=utf-8' },
});
}
async function updateTodos(request) {
const body = await request.text();
const ip = request.headers.get(IPHEADER);
const myKey = `data-${ip}`;
try {
JSON.parse(body);
await setCache(myKey, body);
return new Response(body, { status: 200 });
} catch (err) {
return new Response(err.toString(), { status: 500 });
}
}
async function handleRequest(request) {
if (request.method === 'PUT') {
return updateTodos(request);
} else {
return getTodos(request);
}
}
const html_en = todos => `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Todo List</title>
<link href="/css/cdn.jsdelivr.net_npm_tailwindcss_dist_tailwind.min.css" rel="stylesheet"></link>
</head>
<body class="bg-blue-100">
<div class="w-full h-full flex content-center justify-center mt-8">
<div class="bg-white shadow-md rounded px-8 pt-6 py-8 mb-4">
<h1 class="block text-grey-800 text-md font-bold mb-2">Your Account: client-ip</h1>
<div class="flex">
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-800 leading-tight focus:outline-none focus:shadow-outline" type="text" name="name" placeholder="New Todo"></input>
<button class="bg-blue-500 hover:bg-blue-800 text-white font-bold ml-2 py-2 px-4 rounded focus:outline-none focus:shadow-outline" id="create" type="submit" style="white-space: nowrap;">Create</button>
</div>
<div class="mt-4" id="todos"></div>
</div>
</div>
</body>
<script>
window.todos = ${todos}
var updateTodos = function() {
fetch("/todos", { method: "PUT", body: JSON.stringify({ todos: window.todos }) })
populateTodos()
}
var completeTodo = function(evt) {
var checkbox = evt.target
var todoElement = checkbox.parentNode
var newTodoSet = [].concat(window.todos)
var todo = newTodoSet.find(t => t.id == todoElement.dataset.todo)
todo.completed = !todo.completed
window.todos = newTodoSet
updateTodos()
}
var deleteTodo = function(evt) {
var todoElement = evt.target.parentNode
var todoId = todoElement.dataset.todo
window.todos = window.todos.filter(todo => todo.id != todoId)
updateTodos()
}
var populateTodos = function() {
var todoContainer = document.querySelector("#todos")
todoContainer.innerHTML = null
window.todos.forEach(todo => {
var el = document.createElement("div")
el.className = "border-t py-4"
el.dataset.todo = todo.id
var name = document.createElement("span")
name.className = todo.completed ? "line-through" : ""
name.textContent = todo.name
var checkbox = document.createElement("input")
checkbox.className = "mx-4"
checkbox.type = "checkbox"
checkbox.checked = todo.completed ? 1 : 0
checkbox.addEventListener("click", completeTodo)
var deleteButton = document.createElement("button")
deleteButton.className = "bg-red-500 hover:bg-red-800 text-white font-bold py-2 px-4 rounded ml-2 focus:outline-none focus:shadow-outline"
deleteButton.textContent = "Delete"
deleteButton.addEventListener("click", deleteTodo)
el.appendChild(checkbox)
el.appendChild(name)
el.appendChild(deleteButton)
todoContainer.appendChild(el)
})
}
populateTodos()
var createTodo = function() {
var input = document.querySelector("input[name=name]")
if (input.value.length) {
window.todos = [].concat(todos, { id: window.todos.length + 1, name: input.value, completed: false })
input.value = ""
updateTodos()
}
}
document.querySelector("#create").addEventListener("click", createTodo)
</script>
</html>
`;
addEventListener("fetch", event => {
return event.respondWith(handleRequest(event.request))
})