"use strict"; var nms = { stats:{}, // Various internal stats switch_showing:"", // Which switch we are displaying (if any). get nightMode() { return this._nightMode; }, set nightMode(val) { if (val != this._nightMode) { this._nightMode = val; setNightMode(val); } }, /* * FIXME: This should be slightly smarter. */ _now: false, get now() { return this._now }, set now(v) { this._now = v; nmsData.now = v; }, /* * Various setInterval() handlers. See nmsTimer() for how they are * used. * * FIXME: Should just stop using these. */ timers: { playback:false, }, menuShowing:true, /* * This is a list of nms[x] variables that we store in our * settings-cookie when altered and restore on load. */ settingsList:[ 'nightMode', 'menuShowing' ], keyBindings:{ '?':toggleMenu, 'n':toggleNightMode, '1':setMapModeFromN, '2':setMapModeFromN, '3':setMapModeFromN, '4':setMapModeFromN, '5':setMapModeFromN, '6':setMapModeFromN, '7':setMapModeFromN, 'h':moveTimeFromKey, 'j':moveTimeFromKey, 'k':moveTimeFromKey, 'l':moveTimeFromKey, 'p':moveTimeFromKey, 'r':moveTimeFromKey }, /* * Playback controllers and variables */ playback:{ startTime: false, stopTime: false, playing: false, replayTime: 0, replayIncrement: 60 * 60 } }; /* * Returns a handler object. * * This might seem a bit much for 'setInterval()' etc, but it's really more * about self-documentation and predictable ways of configuring timers. */ function nmsTimer(handler, interval, name, description) { this.handler = handler; this.handle = false; this.interval = parseInt(interval); this.name = name; this.description = description; this.start = function() { if (this.handle) { this.stop(); } this.handle = setInterval(this.handler,this.interval); }; this.stop = function() { if (this.handle) clearInterval(this.handle); this.handle = false; }; this.setInterval = function(interval) { var started = this.handle == false ? false : true; this.stop(); this.interval = parseInt(interval); if (started) this.start(); }; } /* * Convenience function that doesn't support huge numbers, and it's easier * to comment than to fix. But not really, but I'm not fixing it anyway. */ function byteCount(bytes) { var units = ['', 'K', 'M', 'G', 'T', 'P']; var i = 0; while (bytes > 1024) { bytes = bytes / 1024; i++; } return bytes.toFixed(1) + units[i]; } /* * Definitely not a way to toggle night mode. Does something COMPLETELY * DIFFERENT. */ function toggleNightMode() { nms.nightMode = !nms.nightMode; saveSettings(); } /* * Parse 'now' from user-input. * * Should probably just use stringToEpoch() instead, but alas, not yet. */ function parseNow(now) { if (Date.parse(now)) { // Adjust for timezone when converting from epoch (UTC) to string (local) var d = new Date(now); var timezoneOffset = d.getTimezoneOffset() * -60000; var d = new Date(Date.parse(now) - timezoneOffset); var str = d.getFullYear() + "-" + ("00" + (parseInt(d.getMonth())+1)).slice(-2) + "-" + ("00" + d.getDate()).slice(-2) + "T"; str += ("00" + d.getHours()).slice(-2) + ":" + ("00" + d.getMinutes()).slice(-2) + ":" + ("00" + d.getSeconds()).slice(-2); return str; } if (now == "") return ""; return false; } /* * Convert back and forth between epoch. * * There's no particular reason why I use seconds instead of javascript * microseconds, except to leave the mark of a C coder on this javascript * project. */ function stringToEpoch(t) { var foo = t.toString(); // foo = foo.replace('T',' '); var ret = new Date(Date.parse(foo)); return parseInt(parseInt(ret.valueOf()) / 1000); } /* * Have to pad with zeroes to avoid "17:5:0" instead of the conventional * and more readable "17:05:00". I'm sure there's a better way, but this * works just fine. */ function epochToString(t) { // Adjust for timezone when converting from epoch (UTC) to string (local) var d = new Date(parseInt(t) * parseInt(1000)); var timezoneOffset = d.getTimezoneOffset() * -60; t = t - timezoneOffset; var d = new Date(parseInt(t) * parseInt(1000)); var str = d.getFullYear() + "-"; if (parseInt(d.getMonth()) < 9) str += "0"; str += (parseInt(d.getMonth())+1) + "-"; if (d.getDate() < 10) str += "0"; str += d.getDate() + "T"; if (d.getHours() < 10) str += "0"; str += d.getHours() + ":"; if (d.getMinutes() < 10) str += "0"; str += d.getMinutes() + ":"; if (d.getSeconds() < 10) str += "0"; str += d.getSeconds(); return str; } function localEpochToString(t) { var d = new Date(parseInt(t) * parseInt(1000)); var timezoneOffset = d.getTimezoneOffset() * -60; t = t + timezoneOffset; return epochToString(t); } /* * Start replaying historical data. */ nms.playback.startReplay = function(startTime,stopTime) { if(!startTime || !stopTime) return false; nms.playback.pause(); nms.playback.startTime = stringToEpoch(startTime); nms.playback.stopTime = stringToEpoch(stopTime); nms.now = epochToString(nms.playback.startTime); nms.playback.play(); } /* * Pause playback */ nms.playback.pause = function() { nms.timers.playback.stop(); nms.playback.playing = false; } /* * Start playback */ nms.playback.play = function() { nms.playback.tick(); nms.timers.playback.start(); nms.playback.playing = true; } /* * Toggle playback */ nms.playback.toggle = function() { if(nms.playback.playing) { nms.playback.pause(); } else { nms.playback.play(); } } /* * Jump to place in time */ nms.playback.setNow = function(now) { var now = parseNow(now); nms.now = now; nms.playback.stopTime = false; nms.playback.startTime = false; nms.playback.tick(); } /* * Step forwards or backwards in timer */ nms.playback.stepTime = function(n) { var now = getNowEpoch(); var newtime = parseInt(now) + parseInt(n); nms.now = epochToString(parseInt(newtime)); if(!nms.playback.playing) nms.playback.tick(); } /* * Ticker to trigger updates, and advance time if replaying * * This is run on a timer (nms.timers.tick) every second while unpaused */ nms.playback.tick = function() { nms.playback.replayTime = getNowEpoch(); // If outside start-/stopTime, remove limits and pause playback if (nms.playback.stopTime && (nms.playback.replayTime >= nms.playback.stopTime || nms.playback.replayTime < nms.playback.startTime)) { nms.playback.stopTime = false; nms.playback.startTime = false; nms.playback.pause(); return; } // If past actual datetime, go live if (nms.playback.replayTime > parseInt(Date.now() / 1000)) { nms.now = false; } // If we are still replaying, advance time if(nms.now !== false && nms.playback.playing) { nms.playback.stepTime(nms.playback.replayIncrement); } } /* * Helper function for safely getting a valid now-epoch */ function getNowEpoch() { if (nms.now && nms.now != 0) return stringToEpoch(nms.now); else return parseInt(Date.now() / 1000); } function hideSwitch() { _hideSwitch(); nmsData.unregisterHandler("comments","switchshower"); } /* * Hide switch info-box */ function _hideSwitch() { var swtop = document.getElementById("info-switch-parent"); var switchele = document.getElementById("info-switch-table"); var comments = document.getElementById("info-switch-comments-table"); var commentbox; if (switchele != undefined) switchele.parentNode.removeChild(switchele); if (comments != undefined) comments.parentNode.removeChild(comments); commentbox = document.getElementById("commentbox"); if (commentbox != undefined) commentbox.parentNode.removeChild(commentbox); swtop.style.display = 'none'; nms.switch_showing = ""; } function showSwitch(x) { nmsData.addHandler("comments","switchshower",_showSwitch,x); _showSwitch(x); } /* * Display info on switch "x" in the info-box * * FIXME: THIS IS A MONSTROSITY. */ function _showSwitch(x) { var sw = nmsData.switches["switches"][x]; var swm = nmsData.smanagement.switches[x]; var swtop = document.getElementById("info-switch-parent"); var swpanel = document.getElementById("info-switch-panel-body"); var swtitle = document.getElementById("info-switch-title"); var tr; var td1; var td2; _hideSwitch(); nms.switch_showing = x; var switchele = document.createElement("table"); switchele.id = "info-switch-table"; switchele.className = "table"; switchele.classList.add("table"); switchele.classList.add("table-condensed"); swtitle.innerHTML = x + ''; for (var v in sw) { if (v == "placement") { continue; } tr = switchele.insertRow(-1); td1 = tr.insertCell(0); td2 = tr.insertCell(1); td1.innerHTML = v; td2.innerHTML = sw[v]; } for (var v in swm) { tr = switchele.insertRow(-1); td1 = tr.insertCell(0); td2 = tr.insertCell(1); td1.innerHTML = v; td2.innerHTML = swm[v]; } var comments = document.createElement("table"); comments.id = "info-switch-comments-table"; comments.className = "table table-condensed"; var cap = document.createElement("caption"); cap.textContent = "Comments"; comments.appendChild(cap); var has_comment = false; if (nmsData.comments.comments == undefined || nmsData.comments.comments[x] == undefined) { } else { for (var c in nmsData.comments.comments[x]["comments"]) { var comment = nmsData.comments.comments[x]["comments"][c]; has_comment = true; if (comment["state"] == "active" || comment["state"] == "persist" || comment["state"] == "inactive") { tr = comments.insertRow(-1); var col; if (comment["state"] == "active") col = "danger"; else if (comment["state"] == "inactive") col = false; else col = "info"; tr.className = col; tr.id = "commentRow" + comment["id"]; td1 = tr.insertCell(0); td2 = tr.insertCell(1); td1.style.whiteSpace = "nowrap"; td1.style.width = "8em"; var txt = '