Add files via upload
diff --git a/js/autocomplete.js b/js/autocomplete.js
index 7751bc1..107b03a 100644
--- a/js/autocomplete.js
+++ b/js/autocomplete.js
@@ -1,3 +1,5 @@
+// *********** HERE STARTS autocomplete.js *************
+
function autocomplete(inp, obj, act) {
/*the autocomplete function takes two arguments,
the text field element and an objay of possible autocompleted values:*/
@@ -41,10 +43,17 @@
var n = this.dataset.id;
inp.value = obj[n].name;
+ var node = null;
+
+ s.graph.nodes().forEach( function(nnode) {
+ if(nnode.id == n) node = nnode;
+ });
+
+
switch (act) {
case "search":
// Move camera to desired node
- cameraGoto(obj[n].x, obj[n].y);
+ cameraGoto(node.x, node.y);
break;
case "addEdge":
// @TODO: Add an edge between A and B
diff --git a/js/camera.js b/js/camera.js
index ac4894f..44e9f5d 100644
--- a/js/camera.js
+++ b/js/camera.js
@@ -1,3 +1,6 @@
+// *********** HERE STARTS camera.js *************
+
+
window.addEventListener('load', initCamera);
function cameraGoto(nodeX, nodeY) {
@@ -7,16 +10,44 @@
);
}
-function initCamera() {
- document.querySelector("#zoomin").addEventListener("click", function() {
- s.camera.goTo({
- ratio: Math.max(s.camera.settings("zoomMin"), s.camera.ratio / Math.sqrt(2))
- });
- });
+function is_touch_device() {
+ var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
+ var mq = function(query) {
+ return window.matchMedia(query).matches;
+ }
- document.querySelector("#zoomout").addEventListener("click", function() {
- s.camera.goTo({
- ratio: Math.min(s.camera.settings("zoomMax"), s.camera.ratio * Math.sqrt(2))
+ if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
+ return true;
+ }
+
+ // include the 'heartz' as a way to have a non matching MQ to help terminate the join
+ // https://git.io/vznFH
+ var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
+ return mq(query);
+}
+
+function initCamera() {
+
+ if(!is_touch_device()) {
+
+ document.querySelector("#zoomin").addEventListener("click", function() {
+ s.camera.goTo({
+ ratio: Math.max(s.camera.settings("zoomMin"), s.camera.ratio / Math.sqrt(2))
+ });
});
- });
+
+ document.querySelector("#zoomout").addEventListener("click", function() {
+ s.camera.goTo({
+ ratio: Math.min(s.camera.settings("zoomMax"), s.camera.ratio * Math.sqrt(2))
+ });
+ });
+ }
+ else{
+ document.querySelector("#zoomin").style.display = "none";
+ document.querySelector("#zoomout").style.display = "none";
+
+ document.querySelector("#circle-mode").style.bottom = "110px";
+ document.querySelector("#settings").style.bottom = "60px";
+ document.querySelector("#search").style.bottom = "10px";
+ }
}
diff --git a/js/circle-mode.js b/js/circle-mode.js
index ea5f423..d5ecff3 100644
--- a/js/circle-mode.js
+++ b/js/circle-mode.js
@@ -1,9 +1,11 @@
+// *********** HERE STARTS circle-mode.js *************
+
window.addEventListener("load", initCircleMode);
circleMode = false;
function initCircleMode() {
- document.querySelector("#circle-mode").addEventListener('click', function() {
+ document.querySelector("#circle-mode").addEventListener('click', function() {
if(circleMode) {
circleMode = false;
document.querySelector("#circle-mode i").innerText = "trip_origin";
@@ -29,4 +31,22 @@
s.refresh();
}
});
+}
+
+function isInRect (x, y, rect) {
+ if (x < -10000 || x > 10000) return true;
+ if (y < -10000 || y > 10000) return true;
+
+ var ans = true;
+ var c = crossProd (rect[0], rect[1], x, y);
+
+ for(var i=1; i<4; i++) {
+ var temp = crossProd (rect[i], rect[(i+1)%4], x, y);
+ if (c*temp < 0) ans = false;
+ }
+ return ans;
+}
+
+function crossProd(r1, r2, x, y) {
+ return r1[0]*r2[1] + r2[0]*y + x*r1[1] - r1[0]*y - r2[0]*r1[1] - x*r2[1];
}
\ No newline at end of file
diff --git a/js/dialog.js b/js/dialog.js
index 275fb0c..ff3268f 100644
--- a/js/dialog.js
+++ b/js/dialog.js
@@ -1,3 +1,5 @@
+// *********** HERE STARTS dialog.js *************
+
window.addEventListener("load", initDialog);
var dialog = {
diff --git a/js/easter-egg.js b/js/easter-egg.js
index ac73b2a..35dce24 100644
--- a/js/easter-egg.js
+++ b/js/easter-egg.js
@@ -1,3 +1,5 @@
+// *********** HERE STARTS easter-egg.js *************
+
window.addEventListener("load", initEasterEgg);
var seq = [38, 38, 40, 40, 37, 39, 37, 39, 65, 66, 13];
diff --git a/js/graf.js b/js/graf.js
index feab604..155ce2d 100644
--- a/js/graf.js
+++ b/js/graf.js
@@ -1,3 +1,5 @@
+// *********** HERE STARTS graf.js *************
+
window.addEventListener("load", initGraf);
// s is the sigma graph
@@ -46,7 +48,7 @@
edgeColor: "default",
defaultLabelColor: "#fff",
autoRescale: false,
- zoomMax: 10,
+ zoomMax: 30,
// enableEdgeHovering: true,
font: "Roboto",
labelThreshold: 5
@@ -60,11 +62,19 @@
graf = JSON.parse(responseText);
// does graf.nodes have a size attribute?
- var sizegraf = 0;
+ var rectBorrar = [[0,0], [0,0], [0,0], [0,0]];
for (var i in graf.nodes) {
- sizegraf++;
+ if (graf.nodes[i].name == "Erase") rectBorrar[0] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ if (graf.nodes[i].name == "Borrar") rectBorrar[1] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ if (graf.nodes[i].name == "Esborrar") rectBorrar[2] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ if (graf.nodes[i].name == "Delete") rectBorrar[3] = [ graf.nodes[i].x , graf.nodes[i].y ];
}
+ var sizegraf = 0;
+ for (var i in graf.nodes) {
+ if ( isInRect(graf.nodes[i].x, graf.nodes[i].y, rectBorrar) ) continue;
+ sizegraf++;
+ }
var nnode = 0;
for (var i in graf.nodes) {
var ncolor = null;
@@ -79,6 +89,8 @@
var newX = 5000*Math.cos( 2*Math.PI*nnode/sizegraf );
var newY = 5000*Math.sin( 2*Math.PI*nnode/sizegraf );
+ if (isInRect(graf.nodes[i].x, graf.nodes[i].y, rectBorrar) ) continue;
+
s.graph.addNode({
// we add color, originalColor, size, originalX..Y, circleX..Y atributes
id: graf.nodes[i].id,
@@ -96,9 +108,12 @@
originalColor: ncolor
});
nnode++;
+
}
for (var i in graf.edges) {
+ if (isInRect(graf.nodes[graf.edges[i].a].x, graf.nodes[graf.edges[i].a].y, rectBorrar)) continue;
+ if (isInRect(graf.nodes[graf.edges[i].b].x, graf.nodes[graf.edges[i].b].y, rectBorrar)) continue;
s.graph.addEdge({
id: i,
@@ -113,7 +128,8 @@
var nodeId = e.data.node.id,
toKeep = s.graph.neighbors(nodeId);
// toKeep[nodeId] = e.data.node;
-
+
+
s.graph.nodes().forEach(function(n) {
if (toKeep[n.id] || n.id == nodeId) {
n.color = n.originalColor;
@@ -131,6 +147,12 @@
});
if (circleMode) {
+ s.graph.nodes().forEach(function (n) {
+ n.x = n.circleX;
+ n.y = n.circleY;
+ n.size = 10;
+ });
+
e.data.node.x = 0;
e.data.node.y = 0;
e.data.node.size = 30;
diff --git a/js/limit-years.js b/js/limit-years.js
index 6d99c37..cbbef95 100644
--- a/js/limit-years.js
+++ b/js/limit-years.js
@@ -1,3 +1,5 @@
+// *********** HERE STARTS limit-years.js *************
+
window.addEventListener("load", addYearList);
var limitYears = false;
@@ -45,10 +47,12 @@
if(yearlist.style.display == "none"){
yearlist.style.display = "block";
+ document.querySelector("#settings i").innerText = "close";
yearLimits = true;
}
else{
yearlist.style.display = "none";
+ document.querySelector("#settings i").innerText = "settings";
yearLimits = true;
}
}
diff --git a/js/script.js b/js/script.js
new file mode 100644
index 0000000..1493ae1
--- /dev/null
+++ b/js/script.js
@@ -0,0 +1,551 @@
+// *********** HERE STARTS circle-mode.js *************
+
+window.addEventListener("load", initCircleMode);
+
+circleMode = false;
+
+function initCircleMode() {
+ document.querySelector("#circle-mode").addEventListener('click', function() {
+ if(circleMode) {
+ circleMode = false;
+ document.querySelector("#circle-mode i").innerText = "trip_origin";
+
+ s.graph.nodes().forEach(function(n) {
+ n.x = n.originalX;
+ n.y = n.originalY;
+ n.size = 10;
+ });
+
+ s.refresh();
+
+ }
+ else {
+ circleMode = true;
+ document.querySelector("#circle-mode i").innerText = "shuffle";
+
+ s.graph.nodes().forEach(function(n) {
+ n.x = n.circleX;
+ n.y = n.circleY;
+ });
+
+ s.refresh();
+ }
+ });
+}
+
+function isInRect (x, y, rect) {
+ if (x < -10000 || x > 10000) return true;
+ if (y < -10000 || y > 10000) return true;
+
+ var ans = true;
+ var c = crossProd (rect[0], rect[1], x, y);
+
+ for(var i=1; i<4; i++) {
+ var temp = crossProd (rect[i], rect[(i+1)%4], x, y);
+ if (c*temp < 0) ans = false;
+ }
+ return ans;
+}
+
+function crossProd(r1, r2, x, y) {
+ return r1[0]*r2[1] + r2[0]*y + x*r1[1] - r1[0]*y - r2[0]*r1[1] - x*r2[1];
+}
+
+
+// *********** HERE STARTS graf.js *************
+
+window.addEventListener("load", initGraf);
+
+// s is the sigma graph
+// graf is the JSON graph
+var s, graf;
+
+// query dario JSON for the graph information
+function xhr(method, url, params, callback) {
+ var http = new XMLHttpRequest();
+ if (method == "POST") {
+ http.open(method, url, true);
+ } else {
+ if (params != "") {
+ http.open(method, url+"?"+params, true);
+ } else {
+ http.open(method, url, true);
+ }
+ }
+ http.onload = function() {
+ if(this.status != 200) {
+ console.warn("Attention, status code "+this.status+" when loading via xhr url "+url);
+ }
+ callback(this.responseText, this.status);
+ };
+ if (method == "POST") {
+ http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
+ http.send(params);
+ } else {
+ http.send();
+ }
+}
+
+
+function initGraf() {
+ // create new methods for sigma library
+ updateSigma();
+
+ // create graf, s is the sigma graf
+ s = new sigma({
+ renderers: [{
+ container: "graf",
+ type: "webgl"
+ }],
+ settings: {
+ defaultEdgeColor: "#fff",
+ edgeColor: "default",
+ defaultLabelColor: "#fff",
+ autoRescale: false,
+ zoomMax: 30,
+ // enableEdgeHovering: true,
+ font: "Roboto",
+ labelThreshold: 5
+ }
+ });
+
+
+ // query for JSON for graph data
+ xhr("GET", "api.php", "action=getgraf", function(responseText, status) {
+ // graf is the JSON data
+ graf = JSON.parse(responseText);
+
+ // does graf.nodes have a size attribute?
+ var rectBorrar = [[0,0], [0,0], [0,0], [0,0]];
+ for (var i in graf.nodes) {
+ if (graf.nodes[i].name == "Erase") rectBorrar[0] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ if (graf.nodes[i].name == "Borrar") rectBorrar[1] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ if (graf.nodes[i].name == "Esborrar") rectBorrar[2] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ if (graf.nodes[i].name == "Delete") rectBorrar[3] = [ graf.nodes[i].x , graf.nodes[i].y ];
+ }
+
+ var sizegraf = 0;
+ for (var i in graf.nodes) {
+ if ( isInRect(graf.nodes[i].x, graf.nodes[i].y, rectBorrar) ) continue;
+ sizegraf++;
+ }
+ var nnode = 0;
+ for (var i in graf.nodes) {
+ var ncolor = null;
+
+ if(graf.nodes[i].sex =="F") ncolor = "#d61c08";
+ else if(graf.nodes[i].sex == "M") ncolor = "#0159aa";
+ else ncolor = "#0ca80a";
+
+ // post-processing for year corrections
+ if(1970 < graf.nodes[i].year && graf.nodes[i].year < 2004) graf.nodes[i].year += 18;
+
+ var newX = 5000*Math.cos( 2*Math.PI*nnode/sizegraf );
+ var newY = 5000*Math.sin( 2*Math.PI*nnode/sizegraf );
+
+ if (isInRect(graf.nodes[i].x, graf.nodes[i].y, rectBorrar) ) continue;
+
+ s.graph.addNode({
+ // we add color, originalColor, size, originalX..Y, circleX..Y atributes
+ id: graf.nodes[i].id,
+ year: graf.nodes[i].year,
+ sex: graf.nodes[i].sex,
+ label: graf.nodes[i].name,
+ x: graf.nodes[i].x,
+ y: graf.nodes[i].y,
+ circleX: newX,
+ circleY: newY,
+ originalX: graf.nodes[i].x,
+ originalY: graf.nodes[i].y,
+ size: 10,
+ color: ncolor,
+ originalColor: ncolor
+ });
+ nnode++;
+
+ }
+
+ for (var i in graf.edges) {
+ if (isInRect(graf.nodes[graf.edges[i].a].x, graf.nodes[graf.edges[i].a].y, rectBorrar)) continue;
+ if (isInRect(graf.nodes[graf.edges[i].b].x, graf.nodes[graf.edges[i].b].y, rectBorrar)) continue;
+
+ s.graph.addEdge({
+ id: i,
+ source: graf.edges[i].a,
+ target: graf.edges[i].b,
+ size: Math.min(4, Math.max((7/(2*Math.pow(20, 2)))*Math.pow(graf.edges[i].votes, 2) + 1/2, 0.5))
+ });
+
+ }
+
+ s.bind('clickNode', function(e) {
+ var nodeId = e.data.node.id,
+ toKeep = s.graph.neighbors(nodeId);
+ // toKeep[nodeId] = e.data.node;
+
+
+ s.graph.nodes().forEach(function(n) {
+ if (toKeep[n.id] || n.id == nodeId) {
+ n.color = n.originalColor;
+ } else {
+ n.color = '#333';
+ }
+ });
+
+ s.graph.edges().forEach(function(e) {
+ if ((e.source == nodeId || e.target == nodeId) && (toKeep[e.source] || toKeep[e.target])) {
+ e.color = '#fff';
+ } else {
+ e.color = '#333';
+ }
+ });
+
+ if (circleMode) {
+ s.graph.nodes().forEach(function (n) {
+ n.x = n.circleX;
+ n.y = n.circleY;
+ n.size = 10;
+ });
+
+ e.data.node.x = 0;
+ e.data.node.y = 0;
+ e.data.node.size = 30;
+ }
+
+ s.refresh();
+
+ dialog.show(nodeId, toKeep);
+ });
+
+
+ s.refresh();
+ initSearchBar();
+
+ autocomplete(document.querySelector("#search-input"), graf.nodes, "search");
+ });
+}
+
+function updateSigma() {
+ // returns set of neighouts
+ sigma.classes.graph.addMethod("neighbors", function(nodeId) {
+ var k,
+ neighbors = {},
+ index = this.allNeighborsIndex[nodeId] || [];
+
+ for (k in index) {
+ neighbors[k] = this.nodesIndex[k];
+ }
+
+ return neighbors;
+ });
+
+ // returns number of neighbours from a set of years
+ sigma.classes.graph.addMethod("numNeighborsFromYears", function(nodeId, showYearsCopy) {
+ var k,
+ neighbors = 0,
+ index = this.allNeighborsIndex[nodeId] || [];
+
+ for (k in index) {
+ if(this.nodesIndex){
+ if (showYearsCopy.has("" + this.nodesIndex[k].year)) neighbors++;
+ else if (this.nodesIndex[k].year == 0) neighbors++;
+ }
+ }
+
+ return neighbors;
+ });
+}
+
+
+// *********** HERE STARTS limit-years.js *************
+
+window.addEventListener("load", addYearList);
+
+var limitYears = false;
+var showYears = new Set();
+
+function repaint() {
+ //targetYear: graf.nodes[e.source].year,
+ if(limitYears) {
+ var added = new Set();
+
+ s.graph.nodes().forEach(function(n) {
+ var numNeig = s.graph.numNeighborsFromYears(n.id, showYears);
+
+ if ((n.year == 0 && (n.sex == 'F' || n.sex == 'M') )
+ || numNeig == 0
+ || (!showYears.has("" + n.year) && (n.year != 0) )) {
+ n.hidden = true;
+ }
+ else {
+ n.hidden = false;
+ added.add(n.id);
+ }
+ });
+
+ s.graph.edges().forEach(function(e) {
+ if(!added.has(e.source) && !added.has(e.target)){
+ e.hidden = true;
+ }
+ else e.hidden = false;
+ });
+ }
+ else {
+ s.graph.nodes().forEach(function(n) {
+ n.hidden = false;
+ });
+
+ s.graph.edges().forEach(function(e) {
+ e.hidden = false;
+ });
+ }
+}
+
+function altYearList() {
+ var yearlist = document.querySelector("#year-list");
+
+ if(yearlist.style.display == "none"){
+ yearlist.style.display = "block";
+ document.querySelector("#settings i").innerText = "close";
+ yearLimits = true;
+ }
+ else{
+ yearlist.style.display = "none";
+ document.querySelector("#settings i").innerText = "settings";
+ yearLimits = true;
+ }
+}
+
+function addYearList() {
+ var ylistspan = document.querySelector("#year-list-span")
+ for(var year=2006; year<2019; year++) {
+ var yin = document.createElement("input");
+ yin.type = "checkbox";
+ yin.class = "mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored";
+ yin.name = "" + year;
+ yin.addEventListener("change", function(){
+ limitYears = true;
+
+ if(this.checked) {
+ showYears.add(this.name);
+ }
+ else {
+ showYears.delete(this.name);
+ }
+
+ if(showYears.size == 0) limitYears = false;
+
+ repaint();
+
+ s.refresh();
+ });
+
+ var lab = document.createElement("label");
+ lab.innerHTML = "" + year + "<br>";
+
+ ylistspan.appendChild(yin);
+ ylistspan.appendChild(lab);
+ }
+
+ document.querySelector("#settings").addEventListener("click", altYearList);
+}
+
+// *********** HERE STARTS search-bar.js *************
+
+
+function altSearchBar() {
+ if (document.querySelector(".md-google-search__metacontainer").style.display == "none") {
+ document.querySelector(".md-google-search__metacontainer").style.display = "block";
+ document.querySelector("#search i").innerText = "fullscreen";
+ } else {
+ document.querySelector(".md-google-search__metacontainer").style.display = "none";
+ document.querySelector(".autocomplete-container").style.display = "none";
+ document.querySelector("#search i").innerText = "search";
+ }
+}
+
+function initSearchBar() {
+ document.querySelector("#search").addEventListener("click", altSearchBar);
+ if (window.innerWidth > 700) altSearchBar();
+}
+// *********** HERE STARTS dialog.js *************
+
+window.addEventListener("load", initDialog);
+
+var dialog = {
+ fill: function(data, text, html=false) {
+ var el = document.querySelectorAll("*[data-fill=\""+data+"\"]");
+ for (var i in el) {
+ if (html === true) {
+ el[i].innerHTML = text;
+ } else {
+ el[i].innerText = text;
+ }
+ }
+ },
+ show: function(id, neighbors) {
+ var neighbors = Object.values(neighbors);
+
+ this.fill("name", graf.nodes[id].name);
+ this.fill("year", graf.nodes[id].year);
+ this.fill("sex", graf.nodes[id].sex);
+ this.fill("id", "#"+id);
+ this.fill("n-edges", neighbors.length);
+
+ var list = "";
+ neighbors.forEach(function (a) {
+ list += "<li><b>"+graf.nodes[id].name+" - "+a.label+":</b> "+(graf.edges[id+"_"+a.id] ? graf.edges[id+"_"+a.id].votes : graf.edges[a.id+"_"+id].votes)+" vots</li>";
+ });
+ this.fill("edges", list, true);
+
+ if (window.innerWidth > 700) {
+ document.querySelector("#dialog").style.display = "block";
+ document.querySelector("#backdrop-container").style.display = "block";
+ } else {
+ document.querySelector("#summary-dialog").style.display = "block";
+ }
+ },
+ close: function() {
+ document.querySelector("#dialog").style.display = "none";
+ document.querySelector("#summary-dialog").style.display = "none";
+ document.querySelector("#backdrop-container").style.display = "none";
+
+ s.graph.nodes().forEach(function(n) {
+ n.color = n.originalColor;
+ });
+
+ s.graph.edges().forEach(function(e) {
+ e.color = e.originalColor;
+ });
+
+ if(circleMode) {
+ s.graph.nodes().forEach(function (n) {
+ n.x = n.circleX;
+ n.y = n.circleY;
+ n.size = 10;
+ });
+ }
+ else {
+ s.graph.nodes().forEach(function (n) {
+ n.x = n.originalX;
+ n.y = n.originalY;
+ n.size = 10;
+ });
+ }
+ s.refresh();
+
+ },
+ max: function() {
+ document.querySelector("#summary-dialog").style.display = "none";
+ document.querySelector("#dialog").style.display = "block";
+ },
+ min: function() {
+ document.querySelector("#dialog").style.display = "none";
+ document.querySelector("#summary-dialog").style.display = "block";
+ }
+};
+
+
+function initDialog() {
+ document.querySelector("#quit-dialog").addEventListener("click", dialog.close);
+ document.querySelector("#quit2-dialog").addEventListener("click", dialog.close);
+ document.querySelector("#max-dialog").addEventListener("click", dialog.max);
+ document.querySelector("#min-dialog").addEventListener("click", dialog.min);
+}
+
+// *********** HERE STARTS camera.js *************
+
+
+window.addEventListener('load', initCamera);
+
+function cameraGoto(nodeX, nodeY) {
+ sigma.misc.animation.camera( s.camera,
+ { x: nodeX, y: nodeY, ratio: 1 },
+ { duration: s.settings('animationsTime') || 300 }
+ );
+}
+
+function is_touch_device() {
+ var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
+ var mq = function(query) {
+ return window.matchMedia(query).matches;
+ }
+
+ if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
+ return true;
+ }
+
+ // include the 'heartz' as a way to have a non matching MQ to help terminate the join
+ // https://git.io/vznFH
+ var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
+ return mq(query);
+}
+
+function initCamera() {
+
+ if(!is_touch_device()) {
+
+ document.querySelector("#zoomin").addEventListener("click", function() {
+ s.camera.goTo({
+ ratio: Math.max(s.camera.settings("zoomMin"), s.camera.ratio / Math.sqrt(2))
+ });
+ });
+
+ document.querySelector("#zoomout").addEventListener("click", function() {
+ s.camera.goTo({
+ ratio: Math.min(s.camera.settings("zoomMax"), s.camera.ratio * Math.sqrt(2))
+ });
+ });
+ }
+ else{
+ document.querySelector("#zoomin").style.display = "none";
+ document.querySelector("#zoomout").style.display = "none";
+
+ document.querySelector("#circle-mode").style.bottom = "110px";
+ document.querySelector("#settings").style.bottom = "60px";
+ document.querySelector("#search").style.bottom = "10px";
+ }
+}
+
+// *********** HERE STARTS easter-egg.js *************
+
+window.addEventListener("load", initEasterEgg);
+
+var seq = [38, 38, 40, 40, 37, 39, 37, 39, 65, 66, 13];
+var cur = 0;
+
+function justdoit() {
+ s.graph.nodes().forEach(function(n) {
+ switch(n.color) {
+ case "#d61c08":
+ n.color = "#0159aa";
+ break;
+
+ case "#0159aa":
+ n.color = "#0ca80a";
+ break;
+
+ case "#0ca80a":
+ n.color = "#d61c08";
+ break;
+ }
+ });
+
+ s.refresh();
+ setTimeout(justdoit, 333);
+}
+
+
+function initEasterEgg() {
+ document.addEventListener("keydown", function() {
+ if (event.key == "f" && event.target.getAttribute("id") != "search-input") altSearchBar();
+ if (event.which == seq[cur]) {
+ if (cur < seq.length) {
+ ++cur;
+ if (cur == seq.length) {
+ justdoit();
+ }
+ }
+ } else cur = 0;
+ });
+}
diff --git a/js/search-bar.js b/js/search-bar.js
index a52ee65..e5c8846 100644
--- a/js/search-bar.js
+++ b/js/search-bar.js
@@ -1,15 +1,18 @@
-function altSearchBar() {
- if (document.querySelector(".md-google-search__metacontainer").style.display == "none") {
- document.querySelector(".md-google-search__metacontainer").style.display = "block";
- document.querySelector("#search i").innerText = "fullscreen";
- } else {
- document.querySelector(".md-google-search__metacontainer").style.display = "none";
- document.querySelector(".autocomplete-container").style.display = "none";
- document.querySelector("#search i").innerText = "search";
- }
-}
-
-function initSearchBar() {
- document.querySelector("#search").addEventListener("click", altSearchBar);
- if (window.innerWidth > 700) altSearchBar();
-}
+// *********** HERE STARTS search-bar.js *************
+
+
+function altSearchBar() {
+ if (document.querySelector(".md-google-search__metacontainer").style.display == "none") {
+ document.querySelector(".md-google-search__metacontainer").style.display = "block";
+ document.querySelector("#search i").innerText = "fullscreen";
+ } else {
+ document.querySelector(".md-google-search__metacontainer").style.display = "none";
+ document.querySelector(".autocomplete-container").style.display = "none";
+ document.querySelector("#search i").innerText = "search";
+ }
+}
+
+function initSearchBar() {
+ document.querySelector("#search").addEventListener("click", altSearchBar);
+ if (window.innerWidth > 700) altSearchBar();
+}
diff --git a/js/service-worker.js b/js/service-worker.js
index f5ed189..a70346f 100644
--- a/js/service-worker.js
+++ b/js/service-worker.js
@@ -1,102 +1,102 @@
-/*
- Copyright 2015 Google Inc. All Rights Reserved.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-'use strict';
-
-// Incrementing CACHE_VERSION will kick off the install event and force previously cached
-// resources to be cached again.
-const CACHE_VERSION = 1;
-let CURRENT_CACHES = {
- offline: 'offline-v' + CACHE_VERSION
-};
-const OFFLINE_URL = 'offline.html';
-
-function createCacheBustedRequest(url) {
- let request = new Request(url, {cache: 'reload'});
- // See https://fetch.spec.whatwg.org/#concept-request-mode
- // This is not yet supported in Chrome as of M48, so we need to explicitly check to see
- // if the cache: 'reload' option had any effect.
- if ('cache' in request) {
- return request;
- }
-
- // If {cache: 'reload'} didn't have any effect, append a cache-busting URL parameter instead.
- let bustedUrl = new URL(url, self.location.href);
- bustedUrl.search += (bustedUrl.search ? '&' : '') + 'cachebust=' + Date.now();
- return new Request(bustedUrl);
-}
-
-self.addEventListener('install', event => {
- event.waitUntil(
- // We can't use cache.add() here, since we want OFFLINE_URL to be the cache key, but
- // the actual URL we end up requesting might include a cache-busting parameter.
- fetch(createCacheBustedRequest(OFFLINE_URL)).then(function(response) {
- return caches.open(CURRENT_CACHES.offline).then(function(cache) {
- return cache.put(OFFLINE_URL, response);
- });
- })
- );
-});
-
-self.addEventListener('activate', event => {
- // Delete all caches that aren't named in CURRENT_CACHES.
- // While there is only one cache in this example, the same logic will handle the case where
- // there are multiple versioned caches.
- let expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
- return CURRENT_CACHES[key];
- });
-
- event.waitUntil(
- caches.keys().then(cacheNames => {
- return Promise.all(
- cacheNames.map(cacheName => {
- if (expectedCacheNames.indexOf(cacheName) === -1) {
- // If this cache name isn't present in the array of "expected" cache names,
- // then delete it.
- console.log('Deleting out of date cache:', cacheName);
- return caches.delete(cacheName);
- }
- })
- );
- })
- );
-});
-
-self.addEventListener('fetch', event => {
- // We only want to call event.respondWith() if this is a navigation request
- // for an HTML page.
- // request.mode of 'navigate' is unfortunately not supported in Chrome
- // versions older than 49, so we need to include a less precise fallback,
- // which checks for a GET request with an Accept: text/html header.
- if (event.request.mode === 'navigate' ||
- (event.request.method === 'GET' &&
- event.request.headers.get('accept').includes('text/html'))) {
- console.log('Handling fetch event for', event.request.url);
- event.respondWith(
- fetch(event.request).catch(error => {
- // The catch is only triggered if fetch() throws an exception, which will most likely
- // happen due to the server being unreachable.
- // If fetch() returns a valid HTTP response with an response code in the 4xx or 5xx
- // range, the catch() will NOT be called. If you need custom handling for 4xx or 5xx
- // errors, see https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker/fallback-response
- console.log('Fetch failed; returning offline page instead.', error);
- return caches.match(OFFLINE_URL);
- })
- );
- }
-
- // If our if() condition is false, then this fetch handler won't intercept the request.
- // If there are any other fetch handlers registered, they will get a chance to call
- // event.respondWith(). If no fetch handlers call event.respondWith(), the request will be
- // handled by the browser as if there were no service worker involvement.
-});
+/*
+ Copyright 2015 Google Inc. All Rights Reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+'use strict';
+
+// Incrementing CACHE_VERSION will kick off the install event and force previously cached
+// resources to be cached again.
+const CACHE_VERSION = 1;
+let CURRENT_CACHES = {
+ offline: 'offline-v' + CACHE_VERSION
+};
+const OFFLINE_URL = 'offline.html';
+
+function createCacheBustedRequest(url) {
+ let request = new Request(url, {cache: 'reload'});
+ // See https://fetch.spec.whatwg.org/#concept-request-mode
+ // This is not yet supported in Chrome as of M48, so we need to explicitly check to see
+ // if the cache: 'reload' option had any effect.
+ if ('cache' in request) {
+ return request;
+ }
+
+ // If {cache: 'reload'} didn't have any effect, append a cache-busting URL parameter instead.
+ let bustedUrl = new URL(url, self.location.href);
+ bustedUrl.search += (bustedUrl.search ? '&' : '') + 'cachebust=' + Date.now();
+ return new Request(bustedUrl);
+}
+
+self.addEventListener('install', event => {
+ event.waitUntil(
+ // We can't use cache.add() here, since we want OFFLINE_URL to be the cache key, but
+ // the actual URL we end up requesting might include a cache-busting parameter.
+ fetch(createCacheBustedRequest(OFFLINE_URL)).then(function(response) {
+ return caches.open(CURRENT_CACHES.offline).then(function(cache) {
+ return cache.put(OFFLINE_URL, response);
+ });
+ })
+ );
+});
+
+self.addEventListener('activate', event => {
+ // Delete all caches that aren't named in CURRENT_CACHES.
+ // While there is only one cache in this example, the same logic will handle the case where
+ // there are multiple versioned caches.
+ let expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
+ return CURRENT_CACHES[key];
+ });
+
+ event.waitUntil(
+ caches.keys().then(cacheNames => {
+ return Promise.all(
+ cacheNames.map(cacheName => {
+ if (expectedCacheNames.indexOf(cacheName) === -1) {
+ // If this cache name isn't present in the array of "expected" cache names,
+ // then delete it.
+ console.log('Deleting out of date cache:', cacheName);
+ return caches.delete(cacheName);
+ }
+ })
+ );
+ })
+ );
+});
+
+self.addEventListener('fetch', event => {
+ // We only want to call event.respondWith() if this is a navigation request
+ // for an HTML page.
+ // request.mode of 'navigate' is unfortunately not supported in Chrome
+ // versions older than 49, so we need to include a less precise fallback,
+ // which checks for a GET request with an Accept: text/html header.
+ if (event.request.mode === 'navigate' ||
+ (event.request.method === 'GET' &&
+ event.request.headers.get('accept').includes('text/html'))) {
+ console.log('Handling fetch event for', event.request.url);
+ event.respondWith(
+ fetch(event.request).catch(error => {
+ // The catch is only triggered if fetch() throws an exception, which will most likely
+ // happen due to the server being unreachable.
+ // If fetch() returns a valid HTTP response with an response code in the 4xx or 5xx
+ // range, the catch() will NOT be called. If you need custom handling for 4xx or 5xx
+ // errors, see https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker/fallback-response
+ console.log('Fetch failed; returning offline page instead.', error);
+ return caches.match(OFFLINE_URL);
+ })
+ );
+ }
+
+ // If our if() condition is false, then this fetch handler won't intercept the request.
+ // If there are any other fetch handlers registered, they will get a chance to call
+ // event.respondWith(). If no fetch handlers call event.respondWith(), the request will be
+ // handled by the browser as if there were no service worker involvement.
+});