summaryrefslogtreecommitdiff
path: root/modules/changes/changes.html
diff options
context:
space:
mode:
Diffstat (limited to 'modules/changes/changes.html')
-rw-r--r--modules/changes/changes.html257
1 files changed, 257 insertions, 0 deletions
diff --git a/modules/changes/changes.html b/modules/changes/changes.html
new file mode 100644
index 0000000..cda3da1
--- /dev/null
+++ b/modules/changes/changes.html
@@ -0,0 +1,257 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Website change monitor</title>
+<script>
+"use strict";
+
+var urls=[];
+
+function pad(s,n,c){
+ s=s+"";
+ if(!c)c="0";
+ var fill=c,filllen=n-s.length;
+ if(filllen<=0)return s;
+ while(fill.length<filllen)fill+=c;
+ return fill+s;
+}
+
+function dateformat(date){
+ return date.getFullYear()+"/"+pad(date.getMonth(),2)+"/"+pad(date.getDate(),2)+" "+
+ pad(date.getHours(),2)+":"+pad(date.getMinutes(),2)+":"+pad(date.getSeconds(),2);
+}
+
+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 focusData(data){
+ document.getElementById("timelinecontainer").classList.add("visible");
+ var header=document.getElementById("timelineheader");
+ var tbody=document.getElementById("timelinetbody");
+ if(!header.firstChild)header.appendChild(document.createTextNode(data.url));
+ else header.firstChild.nodeValue=data.url;
+
+ var l=tbody.children,i;
+ for(i=l.length-1;i>=0;i--)tbody.removeChild(l[i]);
+
+ var tr,td,s;
+ for(i=data.timeline.length-1;i>=0;i--){
+ tr=document.createElement("tr");
+ if(i<data.timeline.length-1&&data.timeline[i][1]==data.timeline[i+1][1]){
+ tr.classList.add("repeated");
+ }
+
+ td=document.createElement("td");
+ td.appendChild(document.createTextNode(dateformat(new Date(data.timeline[i][0]))));
+ tr.appendChild(td);
+
+ td=document.createElement("td");
+ s=data.timeline[i][1];
+ if(s==null)s="(error while retrieving page)";
+ td.appendChild(document.createTextNode(s));
+ tr.appendChild(td);
+
+ tbody.appendChild(tr);
+ }
+}
+
+function makeURLtr(url){
+ var tr=document.createElement("tr");
+ var td=document.createElement("td");
+
+ td.appendChild(document.createTextNode(url));
+
+ var e=document.createElement("input");
+ e.type="button";
+ e.classList.add("rowdeletebutton");
+ e.value="X";
+ e.setAttribute("title","Delete URL");
+ e.addEventListener("click",function(ev){
+ ev.stopPropagation();
+ fetch("DELETE","/changes/url",url,function(status,body){
+ if(document.getElementById("timelineheader").firstChild.nodeValue==url){
+ document.getElementById("timelinecontainer").classList.remove("visible");
+ }
+ if(status!=200){
+ alert("Error deleting url: ("+status+") "+body);
+ return;
+ }
+ tr.parentNode.removeChild(tr);
+ updateURLs();
+ });
+ });
+ td.appendChild(e);
+
+ tr.addEventListener("click",function(ev){
+ fetch("GET","/changes/url?url="+encodeURIComponent(url),function(status,body){
+ if(status!=200){
+ alert("Error getting data: ("+status+") "+body);
+ return;
+ }
+ var data;
+ try {
+ data=JSON.parse(body);
+ } catch(e){
+ alert("Server sent invalid data!");
+ console.log("Invalid data:",data);
+ return;
+ }
+ focusData(data);
+ });
+ });
+
+ tr.appendChild(td);
+ return tr;
+}
+
+function updateURLs(){
+ fetch("GET","/changes/urls",function(status,body){
+ urls=JSON.parse(body);
+ if(!urls){
+ urls=[];
+ alert("Error retrieving URLs!");
+ return;
+ }
+ var tbody=document.getElementById("urlstable").firstElementChild;
+ var l=tbody.children,i,tr,td;
+ for(i=l.length-1;i>=0;i--)tbody.removeChild(l[i]);
+ for(i=0;i<urls.length;i++){
+ tbody.appendChild(makeURLtr(urls[i]));
+ }
+ });
+}
+
+function addURLbutton(){
+ var e=document.getElementById("urladdinput");
+ var url=e.value;
+ fetch("POST","/changes/url",url,function(status,body){
+ if(status==200){
+ e.value="";
+ } else {
+ alert("URL submission error: ("+status+") "+body);
+ }
+ updateURLs();
+ });
+}
+
+function addURLkeypress(ev){
+ if(ev.keyCode==10||ev.keyCode==13)addURLbutton();
+}
+
+function sendRefresh(){
+ fetch("POST","/changes/refresh",function(status,body){});
+}
+
+window.addEventListener("load",function(){
+ updateURLs();
+ //setInterval(updateURLs,10*1000);
+});
+</script>
+<style>
+body{
+ font-family:Georgia,Times,serif;
+ font-size:14px;
+}
+h1{
+ /*font-size:28px;*/
+ /*margin:19px 0 19px 0;*/
+}
+#urlscontainer{
+ width:500px;
+}
+#urlstablecontainer{
+ height:130px;
+ border:1px #888 solid;
+ overflow-y:scroll;
+}
+#urlstable{
+ width:100%;
+ border-collapse:collapse;
+}
+#urlstable tbody, #urlstable tr, #urlstable td{
+ width:100%;
+}
+#urlstable tr{
+ cursor:pointer;
+}
+#urlstable tr:hover{
+ background-color:#ddd;
+}
+#urlstable tr:nth-child(2n){
+ background-color:#eee;
+}
+#urlstable td{
+ height:100%;
+ vertical-align:middle;
+}
+#urladdinput{
+ width:300px;
+}
+.rowdeletebutton{
+ color:red;
+ font-family:Monospace;
+ font-weight:bold;
+ float:right;
+ cursor:pointer;
+ padding:0 3px 0 3px;
+ background-color:rgba(255,0,0,0.1);
+ border-radius:2px;
+ border-width:0;
+}
+
+#timelinetbl{
+ border-collapse:collapse;
+}
+#timelinetbl td, #timelinetbl th{
+ border:1px #888 solid;
+}
+
+tr.repeated{
+ color:#aaa;
+ font-size:10px;
+}
+
+#timelinecontainer{
+ display:none;
+}
+#timelinecontainer.visible{
+ display:block;
+}
+</style>
+</head>
+<body>
+<h1>Website change monitor</h1>
+<b>URLs:</b>
+<input type="button" onclick="sendRefresh();" value="Redownload sites">
+<br>
+<div>
+ <div id="urlscontainer">
+ <div id="urlstablecontainer">
+ <table id="urlstable"><tbody></tbody></table>
+ </div>
+ <input type="text" id="urladdinput" onkeypress="addURLkeypress(event);">
+ <input type="button" onclick="addURLbutton();" value="Add URL" title="Add URL to watch list">
+ </div>
+</div>
+<div id="timelinecontainer">
+ <h2 id="timelineheader"></h2>
+ <table id="timelinetbl">
+ <thead><tr><th>Date</th><th>Hash</th></tr></thead>
+ <tbody id="timelinetbody"></tbody>
+ </table>
+</div>
+</body>
+</html>