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 = "

Über HopGlass

"; + var s = "

Über Mehsviewer

"; 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 + "
" + showDistance(d) + " / " + showTq(d) + ""); + line.bindLabel(d.source.node.nodeinfo.hostname + " – " + d.target.node.nodeinfo.hostname + "
" + helper.showDistance(d) + " / " + helper.showTq(d) + ""); line.on("click", router.link(d)); dict[d.id] = line; @@ -275,16 +275,16 @@ define(["map/clientlayer", "map/labelslayer", layerControl.addBaseLayer(layer, layerName); customLayers[layerName] = layer; - if (localStorageTest()) { + if (helper.localStorageTest()) { localStorage.setItem("map/customLayers", JSON.stringify(Object.keys(customLayers))); } } catch (e) { - console.log(e); + console.error(e); } } function contextMenuOpenLayerMenu() { - document.querySelector('.leaflet-control-layers').classList.add('leaflet-control-layers-expanded'); + document.querySelector(".leaflet-control-layers").classList.add("leaflet-control-layers-expanded"); } var el = document.createElement("div"); @@ -322,7 +322,7 @@ define(["map/clientlayer", "map/labelslayer", layerControl = L.control.layers(baseLayers, [], {position: "bottomright"}); layerControl.addTo(map); - if (localStorageTest()) { + if (helper.localStorageTest()) { var d = JSON.parse(localStorage.getItem("map/customLayers")); if (d) { @@ -353,7 +353,7 @@ define(["map/clientlayer", "map/labelslayer", if (map.getZoom() > map.options.maxZoom) { map.setZoom(map.options.maxZoom); } - if (localStorageTest()) { + if (helper.localStorageTest()) { localStorage.setItem("map/selectedLayer", JSON.stringify({name: e.name})); } }); @@ -504,25 +504,25 @@ define(["map/clientlayer", "map/labelslayer", barycenter = L.circle(L.latLng(new L.LatLng(config.fixedCenter.lat, config.fixedCenter.lng)), config.fixedCenter.radius * 1000); } - var nodesOnline = subtract(data.nodes.all.filter(online), data.nodes.new); - var nodesOffline = subtract(data.nodes.all.filter(offline), data.nodes.lost); + var nodesOnline = helper.subtract(data.nodes.all.filter(helper.online), data.nodes.new); + var nodesOffline = helper.subtract(data.nodes.all.filter(helper.offline), data.nodes.lost); - var markersOnline = nodesOnline.filter(has_location) + var markersOnline = nodesOnline.filter(helper.hasLocation) .map(mkMarker(nodeDict, function () { return iconOnline; }, router)); - var markersOffline = nodesOffline.filter(has_location) + var markersOffline = nodesOffline.filter(helper.hasLocation) .map(mkMarker(nodeDict, function () { return iconOffline; }, router)); - var markersNew = data.nodes.new.filter(has_location) + var markersNew = data.nodes.new.filter(helper.hasLocation) .map(mkMarker(nodeDict, function () { return iconNew; }, router)); - var markersLost = data.nodes.lost.filter(has_location) + var markersLost = data.nodes.lost.filter(helper.hasLocation) .map(mkMarker(nodeDict, function (d) { if (d.lastseen.isAfter(moment(data.now).subtract(3, "days"))) { return iconAlert; @@ -540,14 +540,14 @@ define(["map/clientlayer", "map/labelslayer", var rtreeOnlineAll = rbush(9); - rtreeOnlineAll.load(data.nodes.all.filter(online).filter(has_location).map(mapRTree)); + rtreeOnlineAll.load(data.nodes.all.filter(helper.online).filter(helper.hasLocation).map(mapRTree)); clientLayer.setData(rtreeOnlineAll); labelsLayer.setData({ - online: nodesOnline.filter(has_location), - offline: nodesOffline.filter(has_location), - new: data.nodes.new.filter(has_location), - lost: data.nodes.lost.filter(has_location) + online: nodesOnline.filter(helper.hasLocation), + offline: nodesOffline.filter(helper.hasLocation), + new: data.nodes.new.filter(helper.hasLocation), + lost: data.nodes.lost.filter(helper.hasLocation) }); updateView(true); diff --git a/lib/meshstats.js b/lib/meshstats.js index 57ec349..0501870 100644 --- a/lib/meshstats.js +++ b/lib/meshstats.js @@ -1,19 +1,19 @@ -define(function () { +define(["helper"], function (helper) { return function (config) { var self = this; var stats, timestamp; self.setData = function (d) { - var totalNodes = sum(d.nodes.all.map(one)); - var totalOnlineNodes = sum(d.nodes.all.filter(online).map(one)); - var totalNewNodes = sum(d.nodes.new.map(one)); - var totalLostNodes = sum(d.nodes.lost.map(one)); - var totalClients = sum(d.nodes.all.filter(online).map(function (d) { + var totalNodes = helper.sum(d.nodes.all.map(helper.one)); + var totalOnlineNodes = helper.sum(d.nodes.all.filter(helper.online).map(helper.one)); + var totalNewNodes = helper.sum(d.nodes.new.map(helper.one)); + var totalLostNodes = helper.sum(d.nodes.lost.map(helper.one)); + var totalClients = helper.sum(d.nodes.all.filter(helper.online).map(function (d) { return d.statistics.clients ? d.statistics.clients : 0; })); - var totalGateways = sum(d.nodes.all.filter(online).filter(function (d) { + var totalGateways = helper.sum(d.nodes.all.filter(helper.online).filter(function (d) { return d.flags.gateway; - }).map(one)); + }).map(helper.one)); var nodetext = [{count: totalOnlineNodes, label: "online"}, {count: totalNewNodes, label: "neu"}, diff --git a/lib/nodelist.js b/lib/nodelist.js index cd55254..c5d685a 100644 --- a/lib/nodelist.js +++ b/lib/nodelist.js @@ -1,4 +1,4 @@ -define(["sorttable", "virtual-dom"], function (SortTable, V) { +define(["sorttable", "virtual-dom", "helper"], function (SortTable, V, helper) { function getUptime(now, d) { if (d.flags.online && "uptime" in d.statistics) { return Math.round(d.statistics.uptime); @@ -63,7 +63,7 @@ define(["sorttable", "virtual-dom"], function (SortTable, V) { href: "#" }, d.nodeinfo.hostname)); - if (has_location(d)) { + if (helper.hasLocation(d)) { td1Content.push(V.h("span", {className: "icon ion-location"})); } diff --git a/lib/proportions.js b/lib/proportions.js index 6df291b..6756829 100644 --- a/lib/proportions.js +++ b/lib/proportions.js @@ -1,5 +1,5 @@ -define(["chroma-js", "virtual-dom", "filters/genericnode"], - function (Chroma, V, Filter) { +define(["chroma-js", "virtual-dom", "filters/genericnode", "helper"], + function (Chroma, V, Filter, helper) { return function (config, filterManager) { var self = this; @@ -24,14 +24,14 @@ define(["chroma-js", "virtual-dom", "filters/genericnode"], siteTable.classList.add("proportion"); function showStatGlobal(o) { - return showStat(o); + return helper.showStat(o); } function count(nodes, key, f) { var dict = {}; nodes.forEach(function (d) { - var v = dictGet(d, key.slice(0)); + var v = helper.dictGet(d, key.slice(0)); if (f !== undefined) { v = f(v); @@ -96,7 +96,7 @@ define(["chroma-js", "virtual-dom", "filters/genericnode"], } self.setData = function (data) { - var onlineNodes = data.nodes.all.filter(online); + var onlineNodes = data.nodes.all.filter(helper.online); var nodes = onlineNodes.concat(data.nodes.lost); var nodeDict = {}; @@ -139,8 +139,12 @@ define(["chroma-js", "virtual-dom", "filters/genericnode"], return b[1] - a[1]; })); fillTable("Firmware", fwTable, fwDict.sort(function (a, b) { - if(b[0] < a[0]) return -1; - if(b[0] > a[0]) return 1; + if (b[0] < a[0]) { + return -1; + } + if (b[0] > a[0]) { + return 1; + } return 0; })); fillTable("Hardware", hwTable, hwDict.sort(function (a, b) { diff --git a/lib/router.js b/lib/router.js index f719cc0..d841d32 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1,4 +1,4 @@ -define(function () { +define(["helper"], function (helper) { return function () { var self = this; var objects = {nodes: {}, links: {}}; @@ -31,7 +31,7 @@ define(function () { } function resetView(push) { - push = trueDefault(push); + push = helper.trueDefault(push); targets.forEach(function (t) { t.resetView(); diff --git a/lib/simplenodelist.js b/lib/simplenodelist.js index 82f017a..8ed0666 100644 --- a/lib/simplenodelist.js +++ b/lib/simplenodelist.js @@ -1,4 +1,4 @@ -define(["moment", "virtual-dom", "moment.de"], function (moment, V) { +define(["moment", "virtual-dom", "helper", "moment.de"], function (moment, V, helper) { return function (nodes, field, router, title) { var self = this; var el, tbody; @@ -46,7 +46,7 @@ define(["moment", "virtual-dom", "moment.de"], function (moment, V) { href: "#" }, d.nodeinfo.hostname)); - if (has_location(d)) { + if (helper.hasLocation(d)) { td1Content.push(V.h("span", {className: "icon ion-location"})); } diff --git a/lib/utils/helper.js b/lib/utils/helper.js new file mode 100644 index 0000000..703f86a --- /dev/null +++ b/lib/utils/helper.js @@ -0,0 +1,234 @@ +define({ + get: function (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(); + }); + }, + + getJSON: function (url) { + return require("helper").get(url).then(JSON.parse); + }, + + sortByKey: function (key, d) { + return d.slice().sort(function (a, b) { + return a[key] - b[key]; + }).reverse(); + }, + + limit: function (key, m, d) { + return d.filter(function (d) { + return d[key].isAfter(m); + }); + }, + + sum: function (a) { + return a.reduce(function (a, b) { + return a + b; + }, 0); + }, + + one: function () { + return 1; + }, + + trueDefault: function (d) { + return d === undefined ? true : d; + }, + + dictGet: function (dict, key) { + var k = key.shift(); + + if (!(k in dict)) { + return null; + } + + if (key.length == 0) { + return dict[k]; + } + + return this.dictGet(dict[k], key); + }, + + localStorageTest: function () { + var test = "test"; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch (e) { + return false; + } + }, + + listReplace: function (s, subst) { + for (key in subst) { + var re = new RegExp(key, "g"); + s = s.replace(re, subst[key]); + } + return s; + }, + + /* Helpers working with nodes */ + + offline: function (d) { + return !d.flags.online; + }, + + online: function (d) { + return d.flags.online; + }, + + hasLocation: function (d) { + return "location" in d.nodeinfo && + Math.abs(d.nodeinfo.location.latitude) < 90 && + Math.abs(d.nodeinfo.location.longitude) < 180; + }, + + subtract: function (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 */ + + showDistance: function (d) { + if (isNaN(d.distance)) { + return; + } + + return d.distance.toFixed(0) + " m"; + }, + + showTq: function (d) { + return (1 / d.tq * 100).toFixed(0) + "%"; + }, + + attributeEntry: function (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; + }, + + createIframe: function (opt, width, height) { + var 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; + }, + + showStat: function (o, subst) { + var content, caption; + subst = typeof subst !== "undefined" ? subst : {}; + + if (o.thumbnail) { + content = document.createElement("img"); + content.src = require("helper").listReplace(o.thumbnail, subst); + } + + if (o.caption) { + caption = require("helper").listReplace(o.caption, subst); + + if (!content) { + content = document.createTextNode(caption); + } + } + + if (o.iframe) { + content = require("helper").createIframe(o.iframe, o.width, o.height); + if (o.iframe.src) { + content.src = require("helper").listReplace(o.iframe.src, subst); + } else { + content.src = require("helper").listReplace(o.iframe, subst); + } + } + + var p = document.createElement("p"); + + if (o.href) { + var link = document.createElement("a"); + link.target = "_blank"; + link.href = require("helper").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/package.json b/package.json index c1129bd..88473be 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ }, "devDependencies": { "autoprefixer": "^6.3.6", + "eslint": "^2.10.2", + "eslint-config-defaults": "^9.0.0", "grunt": "^1.0.1", "grunt-bower-install-simple": "^1.2.3", "grunt-check-dependencies": "^0.12.0", @@ -26,24 +28,6 @@ "amd": true, "es6": true, "node": true - }, - "globals": { - "showStat": false, - "attributeEntry": false, - "dictGet": false, - "getJSON": false, - "has_location": false, - "limit": false, - "localStorageTest": false, - "offline": false, - "one": false, - "online": false, - "showDistance": false, - "showTq": false, - "sortByKey": false, - "subtract": false, - "sum": false, - "trueDefault": false } } } diff --git a/tasks/development.js b/tasks/development.js index 933f123..d366a1c 100644 --- a/tasks/development.js +++ b/tasks/development.js @@ -4,9 +4,9 @@ module.exports = function (grunt) { server: { options: { base: { - path: 'build', + path: "build", options: { - index: 'index.html' + index: "index.html" } }, livereload: true @@ -18,7 +18,7 @@ module.exports = function (grunt) { options: { livereload: true }, - files: ["*.css", "app.js", "helper.js", "lib/**/*.js", "*.html"], + files: ["*.css", "app.js", "lib/**/*.js", "*.html"], tasks: ["dev"] }, config: { diff --git a/tasks/linting.js b/tasks/linting.js index 8c43568..5409fd5 100644 --- a/tasks/linting.js +++ b/tasks/linting.js @@ -12,16 +12,6 @@ module.exports = function (grunt) { npm: {} }, eslint: { - options: { - rules: { - "strict": [2, "never"], - "no-multi-spaces": 0, - "no-new": 0, - "no-shadow": 0, - "no-use-before-define": [1, "nofunc"], - "no-underscore-dangle": 0 - } - }, sources: { src: ["app.js", "!Gruntfile.js", "lib/**/*.js"] },