summaryrefslogtreecommitdiff
path: root/modules/datumpjeprik
diff options
context:
space:
mode:
Diffstat (limited to 'modules/datumpjeprik')
-rw-r--r--modules/datumpjeprik/datumpjeprik.html168
-rw-r--r--modules/datumpjeprik/datumpjeprik.js66
2 files changed, 234 insertions, 0 deletions
diff --git a/modules/datumpjeprik/datumpjeprik.html b/modules/datumpjeprik/datumpjeprik.html
new file mode 100644
index 0000000..46a21d3
--- /dev/null
+++ b/modules/datumpjeprik/datumpjeprik.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Datumpje-prik</title>
+<script>
+var today,periodStart,periodEnd,periodWeekStart,periodWeekEnd,periodLength,
+ days,clicked,cantClick=false;
+
+//Sorry. Prototypes are fun. Using dollars to at least separate these from the built-in methods.
+Date.prototype.$dayOfWeek=function(){return (this.getDay()+6)%7;} //monday..sunday = 0..6
+Date.prototype.$startOfDay=function(){return new Date(this-(((this.getHours()*60+this.getMinutes())*60+this.getSeconds())*1000+this.getMilliseconds()));}
+Date.prototype.$addDays=function(n){return new Date(this.valueOf()+n*24*3600*1000);}
+Date.prototype.$addWeeks=function(n){return new Date(this.valueOf()+n*7*24*3600*1000);}
+Date.prototype.$naturalDate=function(){return this.getFullYear()+"-"+("00"+(this.getMonth()+1)).slice(-2)+"-"+("00"+this.getDate()).slice(-2);}
+
+function diffDays(d1,d2){return ~~(Math.abs(d1-d2)/1000/3600/24);}
+
+function localDateStringToDate(s){return new Date(s+"T00:00:00");}
+
+function appendPath(s,p){
+ if(s.length==0)return p;
+ if(p.length==0)return s;
+ if(s[s.length-1]=="/"){
+ if(p[0]=="/")return s+p.slice(1);
+ else return s+p;
+ } else {
+ if(p[0]=="/")return s+p;
+ else return s+"/"+p;
+ }
+}
+
+function setupCalendar(){
+ var cal=document.getElementById("calendar"),
+ maxnum=Math.max.apply(null,days)+1,
+ startOffset=diffDays(periodWeekStart,periodStart),
+ tr,td,span,w,d,idx;
+ cal.innerHTML="";
+ tr=document.createElement("tr");
+ for(d=0;d<7;d++){
+ td=document.createElement("td");
+ td.innerHTML=["mon","tue","wed","thu","fri","sat","sun"][d];
+ tr.appendChild(td);
+ }
+ cal.appendChild(tr);
+ for(w=0;w<~~(periodLength/7);w++){
+ tr=document.createElement("tr");
+ for(d=0;d<7;d++){
+ td=document.createElement("td");
+ if(7*w+d>=startOffset){
+ idx=7*w+d-startOffset;
+ span=document.createElement("span");
+ span.classList.add("calendar-day-fillspan");
+ span.setAttribute("style","width:"+(days[idx]+clicked[idx])/maxnum*100+"%");
+ td.appendChild(span);
+ span=document.createElement("span");
+ span.classList.add("calendar-day-datelabel");
+ span.appendChild(document.createTextNode(periodStart.$addDays(idx).$naturalDate()));
+ td.appendChild(span);
+ if(!cantClick&&!localStorage.getItem("hasSubmitted"))
+ (function(idx){
+ td.addEventListener("click",function(){
+ clicked[idx]=!clicked[idx];
+ setTimeout(setupCalendar,0);
+ },false);
+ })(idx);
+ }
+ tr.appendChild(td);
+ }
+ cal.appendChild(tr);
+ }
+ if(localStorage.getItem("hasSubmitted")){
+ document.getElementById("status").innerHTML="You have already submitted!";
+ document.getElementById("submitbtn").setAttribute("disabled","");
+ } else {
+ document.getElementById("status").style.display="none";
+ document.getElementById("submitbtn").removeAttribute("disabled");
+ }
+}
+
+function submitdays(){
+ var xhr;
+ cantClick=true;
+ xhr=new XMLHttpRequest();
+ xhr.addEventListener("readystatechange",function(ev){
+ var result;
+ if(this.readyState!=4)return;
+ alert(this.responseText);
+ result=JSON.parse(this.responseText);
+ if(result==true){
+ alert("Submitted successfully!");
+ localStorage.setItem("hasSubmitted","true")
+ } else alert("Error while submitting!");
+ },false);
+ xhr.open("POST",location.protocol+"//"+location.host+appendPath(location.pathname,"/adddays"));
+ xhr.send(JSON.stringify(clicked));
+}
+
+
+(function(){
+ var xhr;
+ today=new Date().$startOfDay();
+ xhr=new XMLHttpRequest();
+ xhr.addEventListener("readystatechange",function(ev){
+ var result;
+ if(this.readyState!=4)return;
+ result=JSON.parse(this.responseText);
+ periodStart=new Date(localDateStringToDate(result["periodStart"]));
+ periodEnd=new Date(localDateStringToDate(result["periodEnd"]));
+ periodWeekStart=periodStart.$addDays(-periodStart.$dayOfWeek());
+ periodWeekEnd=periodEnd.$addDays(6-periodEnd.$dayOfWeek());
+ periodLength=diffDays(periodStart,periodEnd)+1;
+ days=Array.apply(null,new Array(periodLength)).map(function(){return 0;});
+ clicked=days.map(function(){return false;});
+ setupCalendar();
+ },false);
+ xhr.open("GET",location.protocol+"//"+location.host+appendPath(location.pathname,"/dates"));
+ xhr.send();
+
+ xhr=new XMLHttpRequest();
+ xhr.addEventListener("readystatechange",function(ev){
+ var result;
+ if(this.readyState!=4)return;
+ days=JSON.parse(this.responseText);
+ setupCalendar();
+ },false);
+ xhr.open("GET",location.protocol+"//"+location.host+appendPath(location.pathname,"/days"));
+ xhr.send();
+})();
+
+window.addEventListener("load",function(){
+ ;
+},false);
+</script>
+<style>
+tbody#calendar > tr{
+ height:40px;
+}
+tbody#calendar > tr > td{
+ position:relative;
+ width:80px;
+ height:inherit;
+ text-align:center;
+ vertical-align:middle;
+ border:1px #ddd solid;
+}
+.calendar-day-fillspan{
+ display:inline-block;
+ position:absolute;
+ background-color:#6f6;
+ opacity:40%;
+ left:0;
+ top:0;
+ height:100%;
+ z-index:-10000;
+}
+.calendar-day-datelabel{
+ color:#888;
+ font-size:8pt;
+}
+</style>
+</head>
+<body>
+<div id="status"></div>
+<table><tbody id="calendar"><tr><td>Loading...</td></tr></tbody></table>
+<input id="submitbtn" type="button" onclick="submitdays()" value="Submit your days">
+</body>
+</html>
diff --git a/modules/datumpjeprik/datumpjeprik.js b/modules/datumpjeprik/datumpjeprik.js
new file mode 100644
index 0000000..dc56759
--- /dev/null
+++ b/modules/datumpjeprik/datumpjeprik.js
@@ -0,0 +1,66 @@
+var cmn=require("../$common.js");
+var persist=require("node-persist"),
+ util=require("util");
+
+//Sorry. Prototypes are fun. Using dollars to at least separate these from the built-in methods.
+Date.prototype.$dayOfWeek=function(){return (this.getDay()+6)%7;} //monday..sunday = 0..6
+Date.prototype.$startOfDay=function(){return new Date(this-(((this.getHours()*60+this.getMinutes())*60+this.getSeconds())*1000+this.getMilliseconds()));}
+Date.prototype.$addDays=function(n){return new Date(this.valueOf()+n*24*3600*1000);}
+Date.prototype.$addWeeks=function(n){return new Date(this.valueOf()+n*7*24*3600*1000);}
+Date.prototype.$naturalDate=function(){return this.getFullYear()+"-"+("00"+(this.getMonth()+1)).slice(-2)+"-"+("00"+this.getDate()).slice(-2);}
+
+function diffDays(d1,d2){return ~~(Math.abs(d1-d2)/1000/3600/24);}
+
+function localDateStringToDate(s){return new Date(s+"T00:00:00");}
+
+
+var periodStart="2015-04-09",periodEnd="2015-07-05",
+ periodLength=diffDays(localDateStringToDate(periodStart),localDateStringToDate(periodEnd))+1;
+
+persist=persist.create({
+ dir:"persist/datumpjeprik",
+ continuous:false,
+ interval:false
+});
+persist.initSync();
+
+function ensureInitialised(){
+ var days;
+ days=persist.getItem("days");
+ if(!days||days.length!=periodLength){
+ days=Array.apply(null,new Array(periodLength)).map(function(){return 0;});
+ persist.setItemSync("days",days);
+ }
+}
+ensureInitialised();
+
+module.exports=function(app,io,moddir){
+ app.get("/datumpjeprik",function(req,res){
+ res.set("Content-Type","text/html");
+ res.sendFile(moddir+"/datumpjeprik.html");
+ });
+ app.get("/datumpjeprik/dates",function(req,res){
+ res.set("Content-Type","text/json");
+ res.send('{"periodStart":"'+periodStart+'","periodEnd":"'+periodEnd+'"}');
+ });
+ app.get("/datumpjeprik/days",function(req,res){
+ ensureInitialised();
+ res.set("Content-Type","text/json");
+ res.send(persist.getItem("days"));
+ });
+ app.post("/datumpjeprik/adddays",function(req,res){
+ var newdays;
+ console.log(req.body);
+ try{
+ newdays=JSON.parse(req.body);
+ if(newdays.length!=periodLength)throw new Error("length mismatch");
+ if(!newdays.map(function(v){return typeof v=="boolean";}).reduce(function(a,b){return a&&b;}))throw new Error("not all bools");
+ ensureInitialised();
+ persist.setItemSync("days",persist.getItem("days").map(function(v,i){return v+newdays[i];}));
+ res.send("true");
+ } catch(e){
+ res.send("[false,\""+e.message+"\"]");
+ return;
+ }
+ });
+};