summaryrefslogtreecommitdiff
path: root/modules/todo/todo.html
diff options
context:
space:
mode:
Diffstat (limited to 'modules/todo/todo.html')
-rw-r--r--modules/todo/todo.html236
1 files changed, 236 insertions, 0 deletions
diff --git a/modules/todo/todo.html b/modules/todo/todo.html
new file mode 100644
index 0000000..ae13163
--- /dev/null
+++ b/modules/todo/todo.html
@@ -0,0 +1,236 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>TODO</title>
+<script>
+"use strict";
+
+function fetch(method,url,data/*?*/,cb){
+ if(!cb){
+ cb=data;
+ data=undefined;
+ if(!cb)throw new Error("No callback passed to fetch");
+ }
+ var xhr=new XMLHttpRequest();
+ xhr.onreadystatechange=function(ev){
+ if(xhr.readyState<4)return;
+ cb(xhr.status,xhr.responseText);
+ };
+ xhr.open(method,url);
+ xhr.send(data);
+}
+
+function datesplit(date){
+ return {
+ year:date.getFullYear(),
+ month:date.getMonth(),
+ day:date.getDate(),
+ hour:date.getHours(),
+ min:date.getMinutes(),
+ sec:date.getSeconds()
+ };
+}
+
+function pad(s,n,c){
+ if(c==null)c=" ";
+ else c=c[0];
+ s=s+"";
+ while(s.length<n)s=c+s;
+ return s;
+}
+
+function beginOfDay(date){
+ return new Date(date.getTime()-date.getHours()*3600*1000-date.getMinutes()*60*1000-date.getSeconds()*1000-date.getMilliseconds());
+}
+
+function fancytime(timeS){
+ return pad(timeS.hour,2,"0")+":"+pad(timeS.min,2,"0")+(timeS.sec==0?"":":"+pad(timeS.sec,2,"0"));
+}
+
+function fancydate(date){
+ var now=new Date();
+ var nowS=datesplit(new Date());
+ var dateS=datesplit(date);
+ var diffdays=Math.round((beginOfDay(date).getTime()-beginOfDay(now).getTime())/1000/3600/24);
+ if(date.getTime()<now.getTime()){
+ if(diffdays==0)return "Earlier this day";
+ return -diffdays+" day"+(diffdays==-1?"":"s")+" ago";
+ }
+ if(dateS.year==nowS.year&&dateS.month==nowS.month&&dateS.day==nowS.day){
+ return "Today, "+fancytime(dateS);
+ }
+ var diffweeks=~~(diffdays/7);
+ if(diffweeks>0){
+ return "In "+diffweeks+" week"+(diffweeks==1?"":"s")+", "+diffdays%7+" day"+(diffdays%7==1?"":"s");
+ }
+ return "In "+diffdays+" day"+(diffdays==1?"":"s")+", "+fancytime(dateS);
+}
+
+function tablerowfor(task){
+ var div=document.createElement("div");
+ div.classList.add("task");
+
+ var e=document.createElement("span");
+ e.classList.add("tasksubject");
+ e.appendChild(document.createTextNode(task.subject));
+ div.appendChild(e);
+
+ var float=document.createElement("div");
+ float.classList.add("taskfloat");
+
+ e=document.createElement("span");
+ e.classList.add("taskdate");
+ e.appendChild(document.createTextNode(fancydate(task.date)));
+ e.setAttribute("title",task.date.toString());
+ float.appendChild(e);
+
+ e=document.createElement("span");
+ e.classList.add("taskdelete");
+ e.appendChild(document.createTextNode("X"));
+ e.addEventListener("click",function(ev){
+ if(!confirm("Really delete task \""+task.subject+"\"?"))return
+ fetch("DELETE","/todo/task",task.id,function(status,body){
+ if(status==200)getlist();
+ else alert("Delete failed: "+body);
+ });
+ });
+ float.appendChild(e);
+
+ div.appendChild(float);
+
+ return div;
+}
+
+function refreshlist(list){
+ var listelem=document.getElementById("todolist");
+ listelem.innerHTML="";
+ var rows=[];
+ var i,task;
+ var now=new Date();
+ for(i=0;i<list.length;i++){
+ task=list[i];
+ if(task.repweeks!=0){
+ while(task.date<now){
+ task.date=new Date(task.date.getTime()+task.repweeks*7*24*3600*1000);
+ }
+ }
+ rows.push([task.date,tablerowfor(task)]);
+ }
+ if(rows.length==0){
+ var div=document.createElement("div");
+ div.classList.add("notasks");
+ div.appendChild(document.createTextNode("No tasks :D"));
+ listelem.appendChild(div);
+ return;
+ }
+ rows.sort(function(a,b){return a[0]-b[0];}); //ascending sort on the dates
+ for(i=0;i<rows.length;i++){
+ listelem.appendChild(rows[i][1]);
+ }
+}
+
+function getlist(){
+ fetch("GET","/todo/list",function(status,json){
+ var list;
+ try {
+ list=JSON.parse(json);
+ } catch(e){
+ alert("An error occurred!");
+ return;
+ }
+ var i;
+ for(i=0;i<list.length;i++)list[i].date=new Date(list[i].date);
+ refreshlist(list);
+ });
+}
+
+function doOpenAddTask(ev){
+ document.getElementById("addtaskform").classList.remove("invisible");
+ ev.target.parentNode.removeChild(ev.target);
+}
+
+function doAddTask(ev){
+ var subject=document.getElementById("addtasksubject").value;
+ var repweeks=+document.getElementById("addtaskrepweeks").value;
+ var date=document.getElementById("addtaskdate").value;
+ if(typeof date=="string")date=new Date(date);
+ if(isNaN(repweeks)){
+ alert("Invalid repweeks!");
+ return;
+ }
+ fetch("POST","/todo/task",JSON.stringify({
+ subject:subject,
+ repweeks:repweeks,
+ date:date
+ }),function(status,body){
+ if(status==200){
+ location.href=location.href;
+ return;
+ }
+ alert("Error while adding: "+body);
+ });
+}
+
+window.addEventListener("load",getlist);
+</script>
+<style>
+body{
+ font-family:Georgia,Times,serif;
+ font-size:14px;
+}
+.task{
+ border:1px #ddd solid;
+ border-bottom-width:0px;
+ padding:10px;
+ background-color:#f8f8f8;
+ width:500px;
+}
+.task:last-child{
+ border-bottom-width:1px;
+}
+.tasksubject{
+ font-size:18px;
+ font-weight:bold;
+ margin-left:10px;
+}
+.taskfloat{
+ float:right;
+ text-align:right;
+}
+.taskdate{
+ font-size:12px;
+ font-style:italic;
+ display:inline-block;
+ cursor:help;
+}
+.taskdelete{
+ margin-left:60px;
+ font-size:10px;
+ font-family:sans-serif;
+ color:red;
+ cursor:pointer;
+}
+#addtaskform{
+ border:1px #ddd solid;
+ display:inline-block;
+ padding:5px;
+}
+#addtaskform.invisible{
+ display:none;
+}
+</style>
+</head>
+<body>
+<h1>TODO</h1>
+<div id="todolist"></div>
+<br><br>
+<input type="button" onclick="doOpenAddTask(event)" value="Add task">
+<div id="addtaskform" class="addtaskform invisible">
+ Subject: <input type="text" id="addtasksubject" placeholder="Subject"> <br>
+ Repweeks: <input type="number" id="addtaskrepweeks" placeholder="Repweeks" value="0" min="0"> (0 = no repeat) <br>
+ Date: <input type="datetime" id="addtaskdate" placeholder="YYYY-MM-DD HH:MM:SS" size="25"> <br>
+ <input type="button" onclick="doAddTask(event)" value="Add">
+</div>
+</body>
+</html>