/* One ANSI ramp per session. * * Boards rotated their welcome screens; this draws a palette instead. It is * held in sessionStorage so it stays put while you read and changes when you * come back, rather than flickering on every page load. * * Every ramp is three of the sixteen EGA indices, ordered dark to bright, and * none of them bottom out on the frame blue, which would dissolve the logo's * feet into the chrome. Without JS the CSS defaults apply and nothing is lost. */ (function () { var RAMPS = [ ['#0000aa', '#00aaaa', '#55ffff'], // ice ['#0000aa', '#00aaaa', '#ffffff'], // ice/white ['#00aaaa', '#55ffff', '#ffffff'], // shallow ['#555555', '#00aaaa', '#55ffff'], // slate cyan ['#00aa00', '#55ff55', '#ffffff'], // moss ['#555555', '#00aa00', '#55ff55'], // slate green ['#00aa00', '#00aaaa', '#55ffff'], // verdigris ['#aa0000', '#aa5500', '#ffff55'], // ember ['#aa0000', '#ff5555', '#ffff55'], // fire ['#aa5500', '#ff5555', '#ffff55'], // rust ['#aa5500', '#ffff55', '#ffffff'], // amber ['#555555', '#aaaaaa', '#ffffff'], // mono ['#555555', '#aaaaaa', '#55ffff'], // cold mono ['#aa00aa', '#ff55ff', '#ffffff'], // violet ['#aa0000', '#aa00aa', '#ff55ff'] // sunset ]; var i; try { i = sessionStorage.getItem('ramp'); if (i === null) { i = Math.floor(Math.random() * RAMPS.length); sessionStorage.setItem('ramp', i); } } catch (e) { i = Math.floor(Math.random() * RAMPS.length); } var r = RAMPS[i % RAMPS.length]; var s = document.documentElement.style; s.setProperty('--l1', r[0]); s.setProperty('--l2', r[1]); s.setProperty('--l3', r[2]); })(); /* The prompt accepts commands. * * Numbers mean different things depending on the screen, which is how a board * worked: at the main menu they select an area, inside an area they select a * message. Nothing has to disambiguate because no two things on one screen * claim the same key. Anything typeable carries data-key and the chrome that * marks it, so the brackets are a promise rather than decoration. */ (function () { // The script sits in so the ramp applies before first paint; the // command handler has to wait for a DOM to read its keys out of. if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } function init() { var buf = '', timer; var out = document.getElementById('typed'); if (!out) return; var hint = document.createElement('span'); hint.className = 'hint'; out.parentNode.insertBefore(hint, out.nextSibling.nextSibling); function keys() { var m = {}; [].forEach.call(document.querySelectorAll('[data-key]'), function (a) { m[String(a.dataset.key).trim().toUpperCase()] = { href: a.getAttribute('href'), label: a.textContent.trim().replace(/\s+/g, ' ').slice(0, 44) }; }); return m; } var MAP = keys(); // Echo what the number is pointing at, so a pause is informative rather than // just a delay: you can see it is right and wait, keep typing, or hit Enter. function show() { out.textContent = buf; var hit = MAP[buf]; hint.textContent = hit ? ' ' + hit.label : ''; } function go(k) { var hit = MAP[k]; if (hit) { location.href = hit.href; return true; } return false; } addEventListener('keydown', function (e) { if (e.metaKey || e.ctrlKey || e.altKey) return; var k = e.key; clearTimeout(timer); if (k === 'Enter') { if (buf && !go(buf)) { out.textContent = ''; } buf = ''; show(); e.preventDefault(); return; } if (k === 'Backspace') { buf = buf.slice(0, -1); show(); e.preventDefault(); return; } if (k === 'Escape') { buf = ''; show(); e.preventDefault(); return; } if (/^[0-9]$/.test(k)) { buf += k; show(); clearTimeout(timer); var longer = Object.keys(MAP).some(function (x) { return x.length > buf.length && x.indexOf(buf) === 0; }); if (!longer) { // Nothing longer can match, so settle it now: go, or drop what was // typed so a mistyped number never sticks at the prompt. if (MAP[buf]) { go(buf); } else { buf = ''; show(); } } else if (MAP[buf]) { // Ambiguous: "1" is an area and "12" is an entry further down the same // screen. Terminal menus settled this on a short pause rather than // making every selection need Enter, so this does too. // 1200ms, because the message index runs past 40 and reaching for a // second digit takes longer than a confirmation would. Enter commits // at once for anyone who does not want to wait. timer = setTimeout(function () { go(buf); }, 1200); } e.preventDefault(); return; } if (/^[a-zA-Z]$/.test(k)) { if (go(k.toUpperCase())) e.preventDefault(); } }); } })(); /* The address is stored rot13 so it is not sitting in the HTML for a scraper to * lift. Same trick as tobias.raayoni-last.com. Without JS the fallback text * still reads, spelled out, so nothing is lost but the click. */ (function () { function rot13(s) { return s.replace(/[a-zA-Z]/g, function (c) { return String.fromCharCode((c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26); }); } function init() { [].forEach.call(document.querySelectorAll('.mail[data-r]'), function (el) { var a = document.createElement('a'); a.href = 'mailto:' + rot13(el.dataset.r); a.textContent = rot13(el.dataset.r); el.replaceWith(a); }); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); else init(); })();