diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..f0764d2 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,8 @@ +--- +"extends": + - "defaults/configurations/eslint" + +rules: + "semi": ["error", "always"] + "no-undef": 0 + "no-console": ["error", { allow: ["warn", "error"] }] diff --git a/app.js b/app.js index 899049a..d6a1227 100644 --- a/app.js +++ b/app.js @@ -11,7 +11,7 @@ require.config({ "d3": "../bower_components/d3/d3.min", "virtual-dom": "../bower_components/virtual-dom/dist/virtual-dom", "rbush": "../bower_components/rbush/rbush", - "helper": "../helper" + "helper": "utils/helper" }, shim: { "leaflet.label": ["leaflet"], @@ -23,6 +23,6 @@ require.config({ } }); -require(["main", "helper"], function (main) { - getJSON("config.json").then(main); +require(["main", "helper"], function (main, helper) { + helper.getJSON("config.json").then(main); }); diff --git a/helper.js b/helper.js deleted file mode 100644 index 5ded2f7..0000000 --- a/helper.js +++ /dev/null @@ -1,235 +0,0 @@ -function get(url) { - return new Promise(function (resolve, reject) { - var req = new XMLHttpRequest(); - req.open('GET', url); - - req.onload = function () { - if (req.status == 200) { - resolve(req.response); - } - else { - reject(Error(req.statusText)); - } - }; - - req.onerror = function () { - reject(Error("Network Error")); - }; - - req.send(); - }); -} - -function getJSON(url) { - return get(url).then(JSON.parse) -} - -function sortByKey(key, d) { - return d.slice().sort(function (a, b) { - return a[key] - b[key] - }).reverse() -} - -function limit(key, m, d) { - return d.filter(function (d) { - return d[key].isAfter(m) - }) -} - -function sum(a) { - return a.reduce(function (a, b) { - return a + b - }, 0) -} - -function one() { - return 1 -} - -function trueDefault(d) { - return d === undefined ? true : d -} - -function dictGet(dict, key) { - var k = key.shift(); - - if (!(k in dict)) { - return null; - } - - if (key.length == 0) { - return dict[k]; - } - - return dictGet(dict[k], key) -} - -function localStorageTest() { - var test = 'test'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true - } catch (e) { - return false - } -} - -function listReplace(s, subst) { - for (key in subst) { - var re = new RegExp(key, 'g'); - s = s.replace(re, subst[key]) - } - return s -} - -/* Helpers working with nodes */ - -function offline(d) { - return !d.flags.online -} - -function online(d) { - return d.flags.online -} - -function has_location(d) { - return "location" in d.nodeinfo && - Math.abs(d.nodeinfo.location.latitude) < 90 && - Math.abs(d.nodeinfo.location.longitude) < 180 -} - -function subtract(a, b) { - var ids = {}; - - b.forEach(function (d) { - ids[d.nodeinfo.node_id] = true - }); - - return a.filter(function (d) { - return !(d.nodeinfo.node_id in ids) - }) -} - -/* Helpers working with links */ - -function showDistance(d) { - if (isNaN(d.distance)) { - return; - } - - return d.distance.toFixed(0) + " m" -} - -function showTq(d) { - return (1 / d.tq * 100).toFixed(0) + "%" -} - -/* Infobox stuff (XXX: move to module) */ - -function attributeEntry(el, label, value) { - if (value === null || value == undefined) { - return; - } - - var tr = document.createElement("tr"); - var th = document.createElement("th"); - th.textContent = label; - tr.appendChild(th); - - var td = document.createElement("td"); - - if (typeof value == "function") { - value(td); - } else { - td.appendChild(document.createTextNode(value)); - } - - tr.appendChild(td); - - el.appendChild(tr); - - return td -} - -function createIframe(opt, width, height) { - el = document.createElement("iframe"); - width = typeof width !== 'undefined' ? width : '525px'; - height = typeof height !== 'undefined' ? height : '350px'; - - if (opt.src) { - el.src = opt.src; - } else { - el.src = opt; - } - - if (opt.frameBorder) { - el.frameBorder = opt.frameBorder; - } else { - el.frameBorder = 1; - } - - if (opt.width) { - el.width = opt.width; - } else { - el.width = width; - } - - if (opt.height) { - el.height = opt.height; - } else { - el.height = height; - } - - el.scrolling = "no"; - el.seamless = "seamless"; - - return el -} - -function showStat(o, subst) { - var content, caption; - subst = typeof subst !== 'undefined' ? subst : {}; - - if (o.thumbnail) { - content = document.createElement("img"); - content.src = listReplace(o.thumbnail, subst) - } - - if (o.caption) { - caption = listReplace(o.caption, subst); - - if (!content) { - content = document.createTextNode(caption) - } - } - - if (o.iframe) { - content = createIframe(o.iframe, o.width, o.height); - if (o.iframe.src) { - content.src = listReplace(o.iframe.src, subst); - } else { - content.src = listReplace(o.iframe, subst) - } - } - - var p = document.createElement("p"); - - if (o.href) { - var link = document.createElement("a"); - link.target = "_blank"; - link.href = listReplace(o.href, subst); - link.appendChild(content); - - if (caption && o.thumbnail) { - link.title = caption; - } - - p.appendChild(link) - } else { - p.appendChild(content); - } - - return p -} - diff --git a/lib/about.js b/lib/about.js index f888de1..5c2af90 100644 --- a/lib/about.js +++ b/lib/about.js @@ -3,7 +3,7 @@ define(function () { this.render = function (d) { var el = document.createElement("div"); d.appendChild(el); - var s = "
Mit Doppelklick und Shift+Doppelklick kann man in der Karte "; s += "auch zoomen.
"; diff --git a/lib/filters/genericnode.js b/lib/filters/genericnode.js index 831f575..c4fe7a9 100644 --- a/lib/filters/genericnode.js +++ b/lib/filters/genericnode.js @@ -1,4 +1,4 @@ -define([], function () { +define(["helper"], function (helper) { return function (name, key, value, f) { var negate = false; var refresh; @@ -9,7 +9,7 @@ define([], function () { label.appendChild(strong); function run(d) { - var o = dictGet(d, key.slice(0)); + var o = helper.dictGet(d, key.slice(0)); if (f) { o = f(o); diff --git a/lib/forcegraph.js b/lib/forcegraph.js index 41c8e69..84fb394 100644 --- a/lib/forcegraph.js +++ b/lib/forcegraph.js @@ -1,4 +1,4 @@ -define(["d3"], function (d3) { +define(["d3", "helper"], function (d3, helper) { var margin = 200; var NODE_RADIUS = 15; var LINE_RADIUS = 12; @@ -32,7 +32,7 @@ define(["d3"], function (d3) { } function savePositions() { - if (!localStorageTest()) { + if (!helper.localStorageTest()) { return; } @@ -750,7 +750,7 @@ define(["d3"], function (d3) { return !d.o.node; }); - if (localStorageTest()) { + if (helper.localStorageTest()) { var save = JSON.parse(localStorage.getItem("graph/nodeposition")); if (save) { diff --git a/lib/infobox/link.js b/lib/infobox/link.js index 66f75fc..1f6697e 100644 --- a/lib/infobox/link.js +++ b/lib/infobox/link.js @@ -1,9 +1,9 @@ -define(function () { +define(["helper"], function (helper) { function showStatImg(o, source, target) { var subst = {}; subst["{SOURCE}"] = source; subst["{TARGET}"] = target; - return showStat(o, subst); + return helper.showStat(o, subst); } return function (config, el, router, d) { @@ -17,7 +17,7 @@ define(function () { a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname; h2.appendChild(a1); h2.appendChild(document.createTextNode(" \uF3D6 ")); - h2.className = 'ion-inside'; + h2.className = "ion-inside"; var a2 = document.createElement("a"); a2.href = "#"; a2.onclick = router.node(d.target.node); @@ -28,11 +28,11 @@ define(function () { var attributes = document.createElement("table"); attributes.classList.add("attributes"); - attributeEntry(attributes, "TQ", showTq(d)); - attributeEntry(attributes, "Entfernung", showDistance(d)); - var hw1 = unknown ? null : dictGet(d.source.node.nodeinfo, ["hardware", "model"]); - var hw2 = dictGet(d.target.node.nodeinfo, ["hardware", "model"]); - attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt")); + helper.attributeEntry(attributes, "TQ", helper.showTq(d)); + helper.attributeEntry(attributes, "Entfernung", helper.showDistance(d)); + var hw1 = unknown ? null : helper.dictGet(d.source.node.nodeinfo, ["hardware", "model"]); + var hw2 = helper.dictGet(d.target.node.nodeinfo, ["hardware", "model"]); + helper.attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt")); el.appendChild(attributes); if (config.linkInfos) { diff --git a/lib/infobox/location.js b/lib/infobox/location.js index 9910d33..4695ac4 100644 --- a/lib/infobox/location.js +++ b/lib/infobox/location.js @@ -1,10 +1,10 @@ -define(function () { +define(["helper"], function (helper) { return function (config, el, router, d) { var sidebarTitle = document.createElement("h2"); sidebarTitle.textContent = "Location: " + d.toString(); el.appendChild(sidebarTitle); - getJSON("https://nominatim.openstreetmap.org/reverse?format=json&lat=" + d.lat + "&lon=" + d.lng + "&zoom=18&addressdetails=0") + helper.getJSON("https://nominatim.openstreetmap.org/reverse?format=json&lat=" + d.lat + "&lon=" + d.lng + "&zoom=18&addressdetails=0") .then(function (result) { if (result.display_name) { sidebarTitle.textContent = result.display_name; @@ -84,7 +84,7 @@ define(function () { try { document.execCommand("copy"); } catch (err) { - console.log(err); + console.warn(err); } } diff --git a/lib/infobox/main.js b/lib/infobox/main.js index dc900e4..8f1ef4a 100644 --- a/lib/infobox/main.js +++ b/lib/infobox/main.js @@ -33,17 +33,17 @@ define(["infobox/link", "infobox/node", "infobox/location"], function (Link, Nod self.gotoNode = function (d) { create(); - new Node(config, el, router, d); + Node(config, el, router, d); }; self.gotoLink = function (d) { create(); - new Link(config, el, router, d); + Link(config, el, router, d); }; self.gotoLocation = function (d) { create(); - new Location(config, el, router, d); + Location(config, el, router, d); }; return self; diff --git a/lib/infobox/node.js b/lib/infobox/node.js index a1b2814..a906ff5 100644 --- a/lib/infobox/node.js +++ b/lib/infobox/node.js @@ -1,5 +1,5 @@ -define(["moment", "tablesort", "moment.de"], - function (moment, Tablesort) { +define(["moment", "tablesort", "helper", "moment.de"], + function (moment, Tablesort, helper) { function showGeoURI(d) { function showLatitude(d) { var suffix = Math.sign(d) > -1 ? "' N" : "' S"; @@ -21,7 +21,7 @@ define(["moment", "tablesort", "moment.de"], return a + "° " + min.toFixed(3) + suffix; } - if (!has_location(d)) { + if (!helper.hasLocation(d)) { return undefined; } @@ -49,8 +49,8 @@ define(["moment", "tablesort", "moment.de"], } function showFirmware(d) { - var release = dictGet(d.nodeinfo, ["software", "firmware", "release"]); - var base = dictGet(d.nodeinfo, ["software", "firmware", "base"]); + var release = helper.dictGet(d.nodeinfo, ["software", "firmware", "release"]); + var base = helper.dictGet(d.nodeinfo, ["software", "firmware", "base"]); if (release === null || base === null) { return undefined; @@ -60,7 +60,7 @@ define(["moment", "tablesort", "moment.de"], } function showSite(d, config) { - var site = dictGet(d.nodeinfo, ["system", "site_code"]); + var site = helper.dictGet(d.nodeinfo, ["system", "site_code"]); var rt = site; if (config.siteNames) { config.siteNames.forEach(function (t) { @@ -105,7 +105,7 @@ define(["moment", "tablesort", "moment.de"], } function showIPs(d) { - var ips = dictGet(d.nodeinfo, ["network", "addresses"]); + var ips = helper.dictGet(d.nodeinfo, ["network", "addresses"]); if (ips === null) { return undefined; } @@ -193,7 +193,7 @@ define(["moment", "tablesort", "moment.de"], } function showPages(d) { - var webpages = dictGet(d.nodeinfo, ["pages"]); + var webpages = helper.dictGet(d.nodeinfo, ["pages"]); if (webpages === null) { return undefined; } @@ -227,7 +227,7 @@ define(["moment", "tablesort", "moment.de"], } function showAutoupdate(d) { - var au = dictGet(d.nodeinfo, ["software", "autoupdater"]); + var au = helper.dictGet(d.nodeinfo, ["software", "autoupdater"]); if (!au) { return undefined; } @@ -238,8 +238,8 @@ define(["moment", "tablesort", "moment.de"], function showStatImg(o, d) { var subst = {}; subst["{NODE_ID}"] = d.nodeinfo.node_id ? d.nodeinfo.node_id : "unknown"; - subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_') : "unknown"; - return showStat(o, subst); + subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, "_") : "unknown"; + return helper.showStat(o, subst); } return function (config, el, router, d) { @@ -250,28 +250,28 @@ define(["moment", "tablesort", "moment.de"], var attributes = document.createElement("table"); attributes.classList.add("attributes"); - attributeEntry(attributes, "Status", showStatus(d)); - attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null); - attributeEntry(attributes, "Koordinaten", showGeoURI(d)); + helper.attributeEntry(attributes, "Status", showStatus(d)); + helper.attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null); + helper.attributeEntry(attributes, "Koordinaten", showGeoURI(d)); if (config.showContact) { - attributeEntry(attributes, "Kontakt", dictGet(d.nodeinfo, ["owner", "contact"])); + helper.attributeEntry(attributes, "Kontakt", helper.dictGet(d.nodeinfo, ["owner", "contact"])); } - attributeEntry(attributes, "Hardware", dictGet(d.nodeinfo, ["hardware", "model"])); - attributeEntry(attributes, "Primäre MAC", dictGet(d.nodeinfo, ["network", "mac"])); - attributeEntry(attributes, "Node ID", dictGet(d.nodeinfo, ["node_id"])); - attributeEntry(attributes, "Firmware", showFirmware(d)); - attributeEntry(attributes, "Site", showSite(d, config)); - attributeEntry(attributes, "Uptime", showUptime(d)); - attributeEntry(attributes, "Teil des Netzes", showFirstseen(d)); - attributeEntry(attributes, "Systemlast", showLoad(d)); - attributeEntry(attributes, "Arbeitsspeicher", showRAM(d)); - attributeEntry(attributes, "IP Adressen", showIPs(d)); - attributeEntry(attributes, "Webseite", showPages(d)); - attributeEntry(attributes, "Gewähltes Gateway", dictGet(d.statistics, ["gateway"])); - attributeEntry(attributes, "Autom. Updates", showAutoupdate(d)); - attributeEntry(attributes, "Clients", showClients(d)); + helper.attributeEntry(attributes, "Hardware", helper.dictGet(d.nodeinfo, ["hardware", "model"])); + helper.attributeEntry(attributes, "Primäre MAC", helper.dictGet(d.nodeinfo, ["network", "mac"])); + helper.attributeEntry(attributes, "Node ID", helper.dictGet(d.nodeinfo, ["node_id"])); + helper.attributeEntry(attributes, "Firmware", showFirmware(d)); + helper.attributeEntry(attributes, "Site", showSite(d, config)); + helper.attributeEntry(attributes, "Uptime", showUptime(d)); + helper.attributeEntry(attributes, "Teil des Netzes", showFirstseen(d)); + helper.attributeEntry(attributes, "Systemlast", showLoad(d)); + helper.attributeEntry(attributes, "Arbeitsspeicher", showRAM(d)); + helper.attributeEntry(attributes, "IP Adressen", showIPs(d)); + helper.attributeEntry(attributes, "Webseite", showPages(d)); + helper.attributeEntry(attributes, "Gewähltes Gateway", helper.dictGet(d.statistics, ["gateway"])); + helper.attributeEntry(attributes, "Autom. Updates", showAutoupdate(d)); + helper.attributeEntry(attributes, "Clients", showClients(d)); el.appendChild(attributes); @@ -320,7 +320,7 @@ define(["moment", "tablesort", "moment.de"], var tr = document.createElement("tr"); var td1 = document.createElement("td"); - td1.className = 'ion-inside'; + td1.className = "ion-inside"; td1.appendChild(document.createTextNode(d.incoming ? " \uF3D5 " : " \uF3D6 ")); tr.appendChild(td1); @@ -334,7 +334,7 @@ define(["moment", "tablesort", "moment.de"], a1.onclick = router.node(d.node); td2.appendChild(a1); - if (!unknown && has_location(d.node)) { + if (!unknown && helper.hasLocation(d.node)) { var span = document.createElement("span"); span.classList.add("icon"); span.classList.add("ion-location"); @@ -346,7 +346,7 @@ define(["moment", "tablesort", "moment.de"], var td3 = document.createElement("td"); var a2 = document.createElement("a"); a2.href = "#"; - a2.textContent = showTq(d.link); + a2.textContent = helper.showTq(d.link); a2.onclick = router.link(d.link); td3.appendChild(a2); tr.appendChild(td3); @@ -354,7 +354,7 @@ define(["moment", "tablesort", "moment.de"], var td4 = document.createElement("td"); var a4 = document.createElement("a"); a4.href = "#"; - a4.textContent = showDistance(d.link); + a4.textContent = helper.showDistance(d.link); a4.onclick = router.link(d.link); td4.appendChild(a4); td4.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1); @@ -366,7 +366,7 @@ define(["moment", "tablesort", "moment.de"], table.appendChild(tbody); table.className = "node-links"; - new Tablesort(table); + Tablesort(table); el.appendChild(table); } diff --git a/lib/linklist.js b/lib/linklist.js index b26d45f..597bc6d 100644 --- a/lib/linklist.js +++ b/lib/linklist.js @@ -1,4 +1,4 @@ -define(["sorttable", "virtual-dom"], function (SortTable, V) { +define(["sorttable", "virtual-dom", "helper"], function (SortTable, V, helper) { function linkName(d) { return (d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " – " + d.target.node.nodeinfo.hostname; } @@ -33,8 +33,8 @@ define(["sorttable", "virtual-dom"], function (SortTable, V) { var td1Content = [V.h("a", {href: "#", onclick: router.link(d)}, linkName(d))]; var td1 = V.h("td", td1Content); - var td2 = V.h("td", {style: {color: linkScale(d.tq).hex()}}, showTq(d)); - var td3 = V.h("td", showDistance(d)); + var td2 = V.h("td", {style: {color: linkScale(d.tq).hex()}}, helper.showTq(d)); + var td3 = V.h("td", helper.showDistance(d)); return V.h("tr", [td1, td2, td3]); } diff --git a/lib/main.js b/lib/main.js index 14cd1a1..e5bb777 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,5 +1,5 @@ -define(["moment", "router", "leaflet", "gui", "moment.de"], - function (moment, Router, L, GUI) { +define(["moment", "router", "leaflet", "gui", "helper", "moment.de"], + function (moment, Router, L, GUI, helper) { return function (config) { function handleData(data) { var dataNodes = {}; @@ -19,7 +19,7 @@ define(["moment", "router", "leaflet", "gui", "moment.de"], if (i % 2) { if (data[i].version !== 1) { vererr = "Unsupported graph version: " + data[i].version; - console.log(vererr); //silent fail + console.error(vererr); //silent fail } else { data[i].batadv.links.forEach(rearrangeLinks); dataGraph.batadv.nodes = dataGraph.batadv.nodes.concat(data[i].batadv.nodes); @@ -28,7 +28,7 @@ define(["moment", "router", "leaflet", "gui", "moment.de"], } } else if (data[i].version !== 2) { vererr = "Unsupported nodes version: " + data[i].version; - console.log(vererr); //silent fail + console.error(vererr); //silent fail } else { dataNodes.nodes = dataNodes.nodes.concat(data[i].nodes); dataNodes.timestamp = data[i].timestamp; @@ -47,8 +47,8 @@ define(["moment", "router", "leaflet", "gui", "moment.de"], var now = moment(); var age = moment(now).subtract(config.maxAge, "days"); - var newnodes = limit("firstseen", age, sortByKey("firstseen", nodes).filter(online)); - var lostnodes = limit("lastseen", age, sortByKey("lastseen", nodes).filter(offline)); + var newnodes = helper.limit("firstseen", age, helper.sortByKey("firstseen", nodes).filter(helper.online)); + var lostnodes = helper.limit("lastseen", age, helper.sortByKey("lastseen", nodes).filter(helper.offline)); var graphnodes = {}; @@ -154,6 +154,7 @@ define(["moment", "router", "leaflet", "gui", "moment.de"], } }; } + moment.locale("de"); var router = new Router(); @@ -170,7 +171,7 @@ define(["moment", "router", "leaflet", "gui", "moment.de"], } function update() { - return Promise.all(urls.map(getJSON)) + return Promise.all(urls.map(helper.getJSON)) .then(handleData); } @@ -190,7 +191,7 @@ define(["moment", "router", "leaflet", "gui", "moment.de"], }) .catch(function (e) { document.body.textContent = e; - console.log(e); + console.warn(e); }); }; }); diff --git a/lib/map.js b/lib/map.js index 3c7c6bc..b36ac13 100644 --- a/lib/map.js +++ b/lib/map.js @@ -1,7 +1,7 @@ define(["map/clientlayer", "map/labelslayer", - "d3", "leaflet", "moment", "locationmarker", "rbush", + "d3", "leaflet", "moment", "locationmarker", "rbush", "helper", "leaflet.label", "leaflet.providers", "moment.de"], - function (ClientLayer, LabelsLayer, d3, L, moment, LocationMarker, rbush) { + function (ClientLayer, LabelsLayer, d3, L, moment, LocationMarker, rbush, helper) { var options = { worldCopyJump: true, zoomControl: false @@ -149,7 +149,7 @@ define(["map/clientlayer", "map/labelslayer", line.setStyle(opts); }; - line.bindLabel(d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname + "