diff --git a/www/cgi-bin/puzzles.cgi b/www/cgi-bin/puzzles.cgi index 052d0bc..8a3882c 100755 --- a/www/cgi-bin/puzzles.cgi +++ b/www/cgi-bin/puzzles.cgi @@ -23,7 +23,7 @@ for line in io.lines(koth.path("state/points.log")) do end end -local body = "
\n" +local body = "
\n" for cat, biggest in pairs(max_by_cat) do local points, dirname diff --git a/www/res/main.js b/www/res/main.js index 77ced0c..df42c8d 100644 --- a/www/res/main.js +++ b/www/res/main.js @@ -1,11 +1,9 @@ -var main_proc; +var main_terminal; function Main(element) { - console.log(element); var term = new Terminal(element); this.start = function() { - console.log(element); term.clear(); term.par("Main terminal.") term.par("This is the main terminal. In this terminal you will get your puzzle content and someplace to enter in possible answers. It's probably just going to pull the old URL, steal the body element, and submit it to a new Terminal method for slow-despooling of the content of text nodes.") @@ -17,8 +15,8 @@ function Main(element) { function main_start() { - main_proc = new Main(document.getElementById("main")); - setTimeout(main_proc.start, 2500); + main_terminal = new Main(document.getElementById("main")); + setTimeout(main_terminal.start, 2500); } window.addEventListener("load", main_start); diff --git a/www/res/maven_pro.css b/www/res/maven_pro.css index 32cd48c..07fa78a 100755 --- a/www/res/maven_pro.css +++ b/www/res/maven_pro.css @@ -10,7 +10,7 @@ font-style: normal; } -/* +*/ @font-face { font-family: 'Maven Pro'; diff --git a/www/res/messages.js b/www/res/messages.js index a07863d..556edd7 100644 --- a/www/res/messages.js +++ b/www/res/messages.js @@ -1,4 +1,4 @@ -var messages_proc; +var messages_terminal; function Messages(element) { var term = new Terminal(element); @@ -12,8 +12,8 @@ function Messages(element) { function messages_start() { - messages_proc = new Messages(document.getElementById("messages")); - setTimeout(messages_proc.start, 500); + messages_terminal = new Messages(document.getElementById("messages")); + setTimeout(messages_terminal.start, 500); } window.addEventListener("load", messages_start); diff --git a/www/res/puzzles.js b/www/res/puzzles.js index 8de26cb..a5f5e03 100644 --- a/www/res/puzzles.js +++ b/www/res/puzzles.js @@ -1,19 +1,47 @@ -var puzzles_proc; +var puzzles_terminal; + +var puzzles_url = "hack/puzzles.html"; function Puzzles(element) { var term = new Terminal(element); + var refreshInterval; + + function loaded() { + var doc = this.response; + var puzzles = doc.getElementById("puzzles"); + var h1 = document.createElement("h1"); + + h1.textContent = "Puzzles"; - this.start = function() { term.clear(); - term.par("Puzzles terminal"); - term.par("This is going to show you the list of open puzzles. It should refresh itself periodically, since not refreshing was a source of major confusion in the last setup, at least for kids, who seem not to realize what the reload button in the browser does.") + term.append(h1); + term.append(puzzles); } + + function refresh() { + var myRequest = new XMLHttpRequest(); + myRequest.responseType = "document"; + myRequest.addEventListener("load", loaded); + myRequest.open("GET", puzzles_url); + myRequest.send(); + } + + function start() { + term.clear(); + term.par("Loading..."); + + term.par("This is going to show you the list of open puzzles. It should refresh itself periodically, since not refreshing was a source of major confusion in the last setup, at least for kids, who seem not to realize what the reload button in the browser does.") + + refreshInterval = setInterval(refresh, 20 * 1000); + refresh(); + } + + setTimeout(start, 3000); } function puzzles_start() { - puzzles_proc = new Puzzles(document.getElementById("puzzles")); - setTimeout(puzzles_proc.start, 3000); + puzzles_terminal = new Puzzles(document.getElementById("puzzles")); } window.addEventListener("load", puzzles_start); diff --git a/www/res/style.css b/www/res/style.css index 12ed521..ea8ff6c 100644 --- a/www/res/style.css +++ b/www/res/style.css @@ -1,8 +1,13 @@ +/* @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic); */ +/* @import "maven_pro.css"; */ +@import "lato.css"; + html { background: rgba(61, 50, 44, 0) url(brown-lines.jpg) no-repeat center center fixed; background-size: cover; color: #ccb; height: 100%; + font-family: Lato; } body { @@ -15,7 +20,7 @@ body { display: inline-block; margin: 1%; border: solid black 0.2em; - border-radius: 1em 0.25em 1em 1em; + border-radius: 1em 1em 0.5em 1em; overflow: auto; } @@ -38,8 +43,39 @@ body { height: 70%; } +h1 { + text-align: center; + font-size: 120%; +} + +a:link { + color: #13a5de; +} + +#puzzles dl { + display: inline; +} +#puzzles dd { + margin: 0; + margin-left: 1em; +} + @media (max-width: 52em) { #overview, #messages, #puzzles, #main { width: 96%; } -} \ No newline at end of file +} + +::-webkit-scrollbar { + width: 0.7em; +} + +::-webkit-scrollbar-track { + /* -webkit-box-shadow: inset 0 0 0.5em rgba(200, 200, 200, 0.3); */ + background: rgba(0, 0, 0, 0.2); +} + +::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); + border-radius: 1em; +} diff --git a/www/res/terminal.js b/www/res/terminal.js index fec7de5..852f477 100644 --- a/www/res/terminal.js +++ b/www/res/terminal.js @@ -1,29 +1,6 @@ -function tx(element, text, bps) { - var drawTimer; - - var displayed = ""; - var idx = 0; - function draw() { - displayed += text[idx]; - element.textContent = displayed; - - idx += 1; - if (element.parentNode.lastChild == element) { - element.scrollIntoView(); - } - if (text.length == idx) { - clearInterval(drawTimer); - return; - } - } - - // N81 uses 1 stop bit, and 1 parity bit. - // That works out to exactly 10 bits per byte. - msec = 10000 / bps; - - drawTimer = setInterval(draw, msec); - draw(); -} +// XXX: Hack for chrome not supporting an iterator method on HTMLCollection +HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; +NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; function Terminal(target, bps) { bps = bps || 1200; @@ -31,37 +8,143 @@ function Terminal(target, bps) { var outq = []; var outTimer; - function drawElement() { - var next = outq.shift(); - var out = document.createElement(next[0]); + function tx(nodes, bps, scroll) { + var drawTimer; - target.appendChild(out); - tx(out, next[1], bps); + // Looks like EMCAScript 6 has a yield statement. That'll be nice. + // + // for (var node of nodes) { + // var text = ""; + // for (var c of node._text) { + // text += c; + // node.textContent = text; + // } + // } - if (outq.length == 0) { - clearInterval(outTimer); + var nodeIndex = 0; + var node = nodes[0]; + + var textIndex = 0; + var text = ""; + + function draw() { + var src = node._text; + var c = src[textIndex]; + + text += c; + node.textContent = text; + + textIndex += 1; + if (textIndex == src.length) { + textIndex = 0; + text = ""; + + nodeIndex += 1; + if (nodeIndex == nodes.length) { + clearInterval(drawTimer); + return; + } + node = nodes[nodeIndex]; + } + + if (scroll) { + node.scrollIntoView(); + } } + + // N81 uses 1 stop bit, and 1 parity bit. + // That works out to exactly 10 bits per byte. + msec = 10000 / bps; + + drawTimer = setInterval(draw, msec); + draw(); } - this.clear = function() { - while (target.firstChild) { - target.removeChild(target.firstChild); - } - } - this.enqueue = function(tag, txt) { - outq.push([tag, txt]); + function start() { if (! outTimer) { outTimer = setInterval(drawElement, 150); } } - this.par = function(txt) { - this.enqueue("p", txt); + + function stop() { + if (outTimer) { + clearInterval(outTimer); + outTimer = null; + } } + + function drawElement() { + var element = outq.shift(); + + console.log(element); + if (! element) { + stop(); + return; + } + + tx(element._terminalNodes, bps); + } + + + function prepare(element) { + var nodes = []; + + walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT); + while (walker.nextNode()) { + var node = walker.currentNode; + var text = node.textContent; + + node.textContent = ""; + nodes.push(node); + } + + element._terminalNodes = nodes; + } + + + // The main entry point: works like appendChild + this.append = function(element) { + prepare(element); + target.appendChild(element); + outq.push(element); + start(); + } + + + // A cool effect where it despools children in parallel + this.appendShallow = function(element) { + for (var child of element.childNodes) { + prepare(child); + outq.push(child); + } + target.appendChild(element); + start(); + } + + + this.clear = function() { + stop(); + outq = []; + while (target.firstChild) { + target.removeChild(target.firstChild); + } + } + + + this.par = function(txt) { + var e = document.createElement("p"); + e.textContent = txt; + this.append(e); + } + + this.pre = function(txt) { - this.enqueue("pre", txt); + var e = document.createElement("pre"); + e.textContent = txt; + this.append(e); } }