[TASK] Add semicolon

Most code is writen with semicolon and IDE shows errors in nearly every line
This commit is contained in:
Xaver Maierhofer 2016-05-22 13:23:43 +02:00
parent 4e99d717ed
commit c0726461fb
37 changed files with 2003 additions and 2004 deletions

View File

@ -1,24 +1,24 @@
module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-git-describe")
grunt.loadNpmTasks("grunt-git-describe");
grunt.initConfig({
"git-describe": {
options: {},
default: {}
}
})
});
grunt.registerTask("saveRevision", function() {
grunt.event.once("git-describe", function (rev) {
grunt.option("gitRevision", rev)
})
grunt.task.run("git-describe")
})
grunt.option("gitRevision", rev);
});
grunt.task.run("git-describe");
});
grunt.loadTasks("tasks")
grunt.loadTasks("tasks");
grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"])
grunt.registerTask("lint", ["eslint"])
grunt.registerTask("dev", ["default", "connect:server", "watch"])
}
grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"]);
grunt.registerTask("lint", ["eslint"]);
grunt.registerTask("dev", ["default", "connect:server", "watch"]);
};

6
app.js
View File

@ -29,8 +29,8 @@ require.config({
"tablesort.numeric": ["tablesort"],
"helper": ["numeral-intl"]
}
})
});
require(["main", "helper"], function (main) {
getJSON("config.json").then(main)
})
getJSON("config.json").then(main);
});

View File

@ -6,4 +6,4 @@
wrap: true,
optimize: "uglify",
out: "app-combined.js"
})
});

View File

@ -51,22 +51,22 @@ function trueDefault(d) {
}
function dictGet(dict, key) {
var k = key.shift()
var k = key.shift();
if (!(k in dict))
return null
return null;
if (key.length == 0)
return dict[k]
return dict[k];
return dictGet(dict[k], key)
}
function localStorageTest() {
var test = 'test'
var test = 'test';
try {
localStorage.setItem(test, test)
localStorage.removeItem(test)
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true
} catch(e) {
return false
@ -98,11 +98,11 @@ function has_location(d) {
}
function subtract(a, b) {
var ids = {}
var ids = {};
b.forEach( function (d) {
ids[d.nodeinfo.node_id] = true
})
});
return a.filter( function (d) {
return !(d.nodeinfo.node_id in ids)
@ -113,7 +113,7 @@ function subtract(a, b) {
function showDistance(d) {
if (isNaN(d.distance))
return
return;
return numeral(d.distance).format("0,0") + " m"
}
@ -126,96 +126,96 @@ function showTq(d) {
function attributeEntry(el, label, value) {
if (value === null || value == undefined)
return
return;
var tr = document.createElement("tr")
var th = document.createElement("th")
th.textContent = label
tr.appendChild(th)
var tr = document.createElement("tr");
var th = document.createElement("th");
th.textContent = label;
tr.appendChild(th);
var td = document.createElement("td")
var td = document.createElement("td");
if (typeof value == "function")
value(td)
value(td);
else
td.appendChild(document.createTextNode(value))
td.appendChild(document.createTextNode(value));
tr.appendChild(td)
tr.appendChild(td);
el.appendChild(tr)
el.appendChild(tr);
return td
}
function createIframe(opt, width, height) {
el = document.createElement("iframe")
el = document.createElement("iframe");
width = typeof width !== 'undefined' ? width : '525px';
height = typeof height !== 'undefined' ? height : '350px';
if (opt.src)
el.src = opt.src
el.src = opt.src;
else
el.src = opt
el.src = opt;
if (opt.frameBorder)
el.frameBorder = opt.frameBorder
el.frameBorder = opt.frameBorder;
else
el.frameBorder = 1
el.frameBorder = 1;
if (opt.width)
el.width = opt.width
el.width = opt.width;
else
el.width = width
el.width = width;
if (opt.height)
el.height = opt.height
el.height = opt.height;
else
el.height = height
el.height = height;
el.scrolling = "no"
el.seamless = "seamless"
el.scrolling = "no";
el.seamless = "seamless";
return el
}
function showStat(o, subst) {
var content, caption
var content, caption;
subst = typeof subst !== 'undefined' ? subst : {};
if (o.thumbnail) {
content = document.createElement("img")
content = document.createElement("img");
content.src = listReplace(o.thumbnail, subst)
}
if (o.caption) {
caption = listReplace(o.caption, subst)
caption = listReplace(o.caption, subst);
if (!content)
content = document.createTextNode(caption)
}
if (o.iframe) {
content = createIframe(o.iframe, o.width, o.height)
content = createIframe(o.iframe, o.width, o.height);
if (o.iframe.src)
content.src = listReplace(o.iframe.src, subst)
content.src = listReplace(o.iframe.src, subst);
else
content.src = listReplace(o.iframe, subst)
}
var p = document.createElement("p")
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)
var link = document.createElement("a");
link.target = "_blank";
link.href = listReplace(o.href, subst);
link.appendChild(content);
if (caption && o.thumbnail)
link.title = caption
link.title = caption;
p.appendChild(link)
} else
p.appendChild(content)
p.appendChild(content);
return p
}

View File

@ -1,38 +1,38 @@
define(function () {
return function() {
this.render = function (d) {
var el = document.createElement("div")
d.appendChild(el)
var s = "<h2>Über HopGlass</h2>"
var el = document.createElement("div");
d.appendChild(el);
var s = "<h2>Über HopGlass</h2>";
s += "<p>Mit Doppelklick und Shift+Doppelklick kann man in der Karte "
s += "auch zoomen.</p>"
s += "<p>Mit Doppelklick und Shift+Doppelklick kann man in der Karte ";
s += "auch zoomen.</p>";
s += "<h3>AGPL 3</h3>"
s += "<h3>AGPL 3</h3>";
s += "<p>Copyright (C) Milan Pässler</p>"
s += "<p>Copyright (C) Nils Schneider</p>"
s += "<p>Copyright (C) Milan Pässler</p>";
s += "<p>Copyright (C) Nils Schneider</p>";
s += "<p>This program is free software: you can redistribute it and/or "
s += "modify it under the terms of the GNU Affero General Public "
s += "License as published by the Free Software Foundation, either "
s += "version 3 of the License, or (at your option) any later version.</p>"
s += "<p>This program is free software: you can redistribute it and/or ";
s += "modify it under the terms of the GNU Affero General Public ";
s += "License as published by the Free Software Foundation, either ";
s += "version 3 of the License, or (at your option) any later version.</p>";
s += "<p>This program is distributed in the hope that it will be useful, "
s += "but WITHOUT ANY WARRANTY; without even the implied warranty of "
s += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
s += "GNU Affero General Public License for more details.</p>"
s += "<p>This program is distributed in the hope that it will be useful, ";
s += "but WITHOUT ANY WARRANTY; without even the implied warranty of ";
s += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ";
s += "GNU Affero General Public License for more details.</p>";
s += "<p>You should have received a copy of the GNU Affero General "
s += "Public License along with this program. If not, see "
s += "<a href=\"https://www.gnu.org/licenses/\">"
s += "https://www.gnu.org/licenses/</a>.</p>"
s += "<p>You should have received a copy of the GNU Affero General ";
s += "Public License along with this program. If not, see ";
s += "<a href=\"https://www.gnu.org/licenses/\">";
s += "https://www.gnu.org/licenses/</a>.</p>";
s += "<p>The source code is available at "
s += "<a href=\"https://github.com/plumpudding/hopglass\">"
s += "https://github.com/plumpudding/hopglass</a>."
s += "<p>The source code is available at ";
s += "<a href=\"https://github.com/plumpudding/hopglass\">";
s += "https://github.com/plumpudding/hopglass</a>.";
el.innerHTML = s
}
}
})
el.innerHTML = s;
};
};
});

View File

@ -1,20 +1,20 @@
define([], function () {
return function (tag) {
if (!tag)
tag = "div"
tag = "div";
var self = this
var self = this;
var container = document.createElement(tag)
var container = document.createElement(tag);
self.add = function (d) {
d.render(container)
}
d.render(container);
};
self.render = function (el) {
el.appendChild(container)
}
el.appendChild(container);
};
return self
}
})
return self;
};
});

View File

@ -1,71 +1,71 @@
define(["filters/nodefilter"], function (NodeFilter) {
return function () {
var targets = []
var filterObservers = []
var filters = []
var filteredData
var data
var targets = [];
var filterObservers = [];
var filters = [];
var filteredData;
var data;
function remove(d) {
targets = targets.filter( function (e) { return d !== e } )
targets = targets.filter( function (e) { return d !== e; } );
}
function add(d) {
targets.push(d)
targets.push(d);
if (filteredData !== undefined)
d.setData(filteredData)
d.setData(filteredData);
}
function setData(d) {
data = d
refresh()
data = d;
refresh();
}
function refresh() {
if (data === undefined)
return
return;
var filter = filters.reduce( function (a, f) {
return function (d) {
return a(d) && f.run(d)
}
}, function () { return true })
return a(d) && f.run(d);
};
}, function () { return true; });
filteredData = new NodeFilter(filter)(data)
filteredData = new NodeFilter(filter)(data);
targets.forEach( function (t) {
t.setData(filteredData)
})
t.setData(filteredData);
});
}
function notifyObservers() {
filterObservers.forEach( function (d) {
d.filtersChanged(filters)
})
d.filtersChanged(filters);
});
}
function addFilter(d) {
filters.push(d)
notifyObservers()
d.setRefresh(refresh)
refresh()
filters.push(d);
notifyObservers();
d.setRefresh(refresh);
refresh();
}
function removeFilter(d) {
filters = filters.filter( function (e) { return d !== e } )
notifyObservers()
refresh()
filters = filters.filter( function (e) { return d !== e; } );
notifyObservers();
refresh();
}
function watchFilters(d) {
filterObservers.push(d)
filterObservers.push(d);
d.filtersChanged(filters)
d.filtersChanged(filters);
return function () {
filterObservers = filterObservers.filter( function (e) { return d !== e })
}
filterObservers = filterObservers.filter( function (e) { return d !== e; });
};
}
return { add: add,
@ -75,6 +75,6 @@ define(["filters/nodefilter"], function (NodeFilter) {
removeFilter: removeFilter,
watchFilters: watchFilters,
refresh: refresh
}
}
})
};
};
});

View File

@ -1,40 +1,40 @@
define([], function () {
return function (distributor) {
var container = document.createElement("ul")
container.classList.add("filters")
var div = document.createElement("div")
var container = document.createElement("ul");
container.classList.add("filters");
var div = document.createElement("div");
function render(el) {
el.appendChild(div)
el.appendChild(div);
}
function filtersChanged(filters) {
while (container.firstChild)
container.removeChild(container.firstChild)
container.removeChild(container.firstChild);
filters.forEach( function (d) {
var li = document.createElement("li")
var div = document.createElement("div")
container.appendChild(li)
li.appendChild(div)
d.render(div)
var li = document.createElement("li");
var div = document.createElement("div");
container.appendChild(li);
li.appendChild(div);
d.render(div);
var button = document.createElement("button")
button.textContent = ""
var button = document.createElement("button");
button.textContent = "";
button.onclick = function () {
distributor.removeFilter(d)
}
li.appendChild(button)
})
distributor.removeFilter(d);
};
li.appendChild(button);
});
if (container.parentNode === div && filters.length === 0)
div.removeChild(container)
div.removeChild(container);
else if (filters.length > 0)
div.appendChild(container)
div.appendChild(container);
}
return { render: render,
filtersChanged: filtersChanged
}
}
})
};
};
});

View File

@ -1,52 +1,52 @@
define([], function () {
return function (name, key, value, f) {
var negate = false
var refresh
var negate = false;
var refresh;
var label = document.createElement("label")
var strong = document.createElement("strong")
label.textContent = name + " "
label.appendChild(strong)
var label = document.createElement("label");
var strong = document.createElement("strong");
label.textContent = name + " ";
label.appendChild(strong);
function run(d) {
var o = dictGet(d, key.slice(0))
var o = dictGet(d, key.slice(0));
if (f)
o = f(o)
o = f(o);
return o === value ? !negate : negate
return o === value ? !negate : negate;
}
function setRefresh(f) {
refresh = f
refresh = f;
}
function draw(el) {
if (negate)
el.parentNode.classList.add("not")
el.parentNode.classList.add("not");
else
el.parentNode.classList.remove("not")
el.parentNode.classList.remove("not");
strong.textContent = (negate ? "¬" : "" ) + value
strong.textContent = (negate ? "¬" : "" ) + value;
}
function render(el) {
el.appendChild(label)
draw(el)
el.appendChild(label);
draw(el);
label.onclick = function () {
negate = !negate
negate = !negate;
draw(el)
draw(el);
if (refresh)
refresh()
}
refresh();
};
}
return { run: run,
setRefresh: setRefresh,
render: render
}
}
})
};
};
});

View File

@ -1,34 +1,34 @@
define([], function () {
return function (filter) {
return function (data) {
var n = Object.create(data)
n.nodes = {}
var n = Object.create(data);
n.nodes = {};
for (var key in data.nodes) {
n.nodes[key] = data.nodes[key].filter(filter)
n.nodes[key] = data.nodes[key].filter(filter);
}
var filteredIds = new Set()
var filteredIds = new Set();
n.graph = {}
n.graph = {};
n.graph.nodes = data.graph.nodes.filter( function (d) {
var r
var r;
if (d.node)
r = filter(d.node)
r = filter(d.node);
else
r = filter({})
r = filter({});
if (r)
filteredIds.add(d.id)
filteredIds.add(d.id);
return r
})
return r;
});
n.graph.links = data.graph.links.filter( function (d) {
return filteredIds.has(d.source.id) && filteredIds.has(d.target.id)
})
return filteredIds.has(d.source.id) && filteredIds.has(d.target.id);
});
return n
}
}
})
return n;
};
};
});

File diff suppressed because it is too large Load Diff

View File

@ -6,117 +6,117 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
Nodelist, SimpleNodelist, Infobox, Proportions, ForceGraph,
Title, About, DataDistributor, FilterGUI) {
return function (config, router) {
var self = this
var content
var contentDiv
var self = this;
var content;
var contentDiv;
var linkScale = chroma.scale(chroma.interpolate.bezier(["#04C714", "#FF5500", "#F02311"])).domain([1, 5])
var sidebar
var linkScale = chroma.scale(chroma.interpolate.bezier(["#04C714", "#FF5500", "#F02311"])).domain([1, 5]);
var sidebar;
var buttons = document.createElement("div")
buttons.classList.add("buttons")
var buttons = document.createElement("div");
buttons.classList.add("buttons");
var fanout = new DataDistributor()
var fanoutUnfiltered = new DataDistributor()
fanoutUnfiltered.add(fanout)
var fanout = new DataDistributor();
var fanoutUnfiltered = new DataDistributor();
fanoutUnfiltered.add(fanout);
function removeContent() {
if (!content)
return
return;
router.removeTarget(content)
fanout.remove(content)
router.removeTarget(content);
fanout.remove(content);
content.destroy()
content.destroy();
content = null
content = null;
}
function addContent(K) {
removeContent()
removeContent();
content = new K(config, linkScale, sidebar.getWidth, router, buttons)
content.render(contentDiv)
content = new K(config, linkScale, sidebar.getWidth, router, buttons);
content.render(contentDiv);
fanout.add(content)
router.addTarget(content)
fanout.add(content);
router.addTarget(content);
}
function mkView(K) {
return function () {
addContent(K)
}
addContent(K);
};
}
contentDiv = document.createElement("div")
contentDiv.classList.add("content")
document.body.appendChild(contentDiv)
contentDiv = document.createElement("div");
contentDiv.classList.add("content");
document.body.appendChild(contentDiv);
sidebar = new Sidebar(document.body)
sidebar = new Sidebar(document.body);
contentDiv.appendChild(buttons)
contentDiv.appendChild(buttons);
var buttonToggle = document.createElement("button")
buttonToggle.textContent = "\uF133"
var buttonToggle = document.createElement("button");
buttonToggle.textContent = "\uF133";
buttonToggle.onclick = function () {
if (content.constructor === Map)
router.view("g")
router.view("g");
else
router.view("m")
}
router.view("m");
};
buttons.appendChild(buttonToggle)
buttons.appendChild(buttonToggle);
var title = new Title(config)
var title = new Title(config);
var header = new Container("header")
var infobox = new Infobox(config, sidebar, router)
var tabs = new Tabs()
var overview = new Container()
var meshstats = new Meshstats(config)
var legend = new Legend()
var newnodeslist = new SimpleNodelist("new", "firstseen", router, "Neue Knoten")
var lostnodeslist = new SimpleNodelist("lost", "lastseen", router, "Verschwundene Knoten")
var nodelist = new Nodelist(router)
var linklist = new Linklist(linkScale, router)
var statistics = new Proportions(config, fanout)
var about = new About()
var header = new Container("header");
var infobox = new Infobox(config, sidebar, router);
var tabs = new Tabs();
var overview = new Container();
var meshstats = new Meshstats(config);
var legend = new Legend();
var newnodeslist = new SimpleNodelist("new", "firstseen", router, "Neue Knoten");
var lostnodeslist = new SimpleNodelist("lost", "lastseen", router, "Verschwundene Knoten");
var nodelist = new Nodelist(router);
var linklist = new Linklist(linkScale, router);
var statistics = new Proportions(config, fanout);
var about = new About();
fanoutUnfiltered.add(meshstats)
fanoutUnfiltered.add(newnodeslist)
fanoutUnfiltered.add(lostnodeslist)
fanout.add(nodelist)
fanout.add(linklist)
fanout.add(statistics)
fanoutUnfiltered.add(meshstats);
fanoutUnfiltered.add(newnodeslist);
fanoutUnfiltered.add(lostnodeslist);
fanout.add(nodelist);
fanout.add(linklist);
fanout.add(statistics);
sidebar.add(header)
header.add(meshstats)
header.add(legend)
sidebar.add(header);
header.add(meshstats);
header.add(legend);
overview.add(newnodeslist)
overview.add(lostnodeslist)
overview.add(newnodeslist);
overview.add(lostnodeslist);
var filterGUI = new FilterGUI(fanout)
fanout.watchFilters(filterGUI)
header.add(filterGUI)
var filterGUI = new FilterGUI(fanout);
fanout.watchFilters(filterGUI);
header.add(filterGUI);
sidebar.add(tabs)
tabs.add("Aktuelles", overview)
tabs.add("Knoten", nodelist)
tabs.add("Verbindungen", linklist)
tabs.add("Statistiken", statistics)
tabs.add("Über", about)
sidebar.add(tabs);
tabs.add("Aktuelles", overview);
tabs.add("Knoten", nodelist);
tabs.add("Verbindungen", linklist);
tabs.add("Statistiken", statistics);
tabs.add("Über", about);
router.addTarget(title)
router.addTarget(infobox)
router.addTarget(title);
router.addTarget(infobox);
router.addView("m", mkView(Map))
router.addView("g", mkView(ForceGraph))
router.addView("m", mkView(Map));
router.addView("g", mkView(ForceGraph));
router.view("m")
router.view("m");
self.setData = fanoutUnfiltered.setData
self.setData = fanoutUnfiltered.setData;
return self
}
})
return self;
};
});

View File

@ -1,49 +1,49 @@
define(function () {
function showStatImg(o, source, target) {
var subst = {}
subst["{SOURCE}"] = source
subst["{TARGET}"] = target
return showStat(o, subst)
var subst = {};
subst["{SOURCE}"] = source;
subst["{TARGET}"] = target;
return showStat(o, subst);
}
return function (config, el, router, d) {
var unknown = !(d.source.node)
var h2 = document.createElement("h2")
var a1 = document.createElement("a")
var unknown = !(d.source.node);
var h2 = document.createElement("h2");
var a1 = document.createElement("a");
if (!unknown) {
a1.href = "#"
a1.onclick = router.node(d.source.node)
a1.href = "#";
a1.onclick = router.node(d.source.node);
}
a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname
h2.appendChild(a1)
h2.appendChild(document.createTextNode(" → "))
var a2 = document.createElement("a")
a2.href = "#"
a2.onclick = router.node(d.target.node)
a2.textContent = d.target.node.nodeinfo.hostname
h2.appendChild(a2)
el.appendChild(h2)
a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname;
h2.appendChild(a1);
h2.appendChild(document.createTextNode(" → "));
var a2 = document.createElement("a");
a2.href = "#";
a2.onclick = router.node(d.target.node);
a2.textContent = d.target.node.nodeinfo.hostname;
h2.appendChild(a2);
el.appendChild(h2);
var attributes = document.createElement("table")
attributes.classList.add("attributes")
var attributes = document.createElement("table");
attributes.classList.add("attributes");
attributeEntry(attributes, "TQ", showTq(d))
attributeEntry(attributes, "Entfernung", showDistance(d))
attributeEntry(attributes, "Typ", d.type)
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"))
el.appendChild(attributes)
attributeEntry(attributes, "TQ", showTq(d));
attributeEntry(attributes, "Entfernung", showDistance(d));
attributeEntry(attributes, "Typ", d.type);
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"));
el.appendChild(attributes);
if (config.linkInfos) {
var source = d.source.node_id
var target = d.target.node_id
var source = d.source.node_id;
var target = d.target.node_id;
config.linkInfos.forEach( function (linkInfo) {
var h4 = document.createElement("h4")
h4.textContent = linkInfo.name
el.appendChild(h4)
el.appendChild(showStatImg(linkInfo, source, target))
})
var h4 = document.createElement("h4");
h4.textContent = linkInfo.name;
el.appendChild(h4);
el.appendChild(showStatImg(linkInfo, source, target));
});
}
}
})
};
});

View File

@ -1,100 +1,100 @@
define(function () {
return function (config, el, router, d) {
var sidebarTitle = document.createElement("h2")
sidebarTitle.textContent = "Location: " + d.toString()
el.appendChild(sidebarTitle)
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")
.then(function(result) {
if(result.display_name)
sidebarTitle.textContent = result.display_name
})
sidebarTitle.textContent = result.display_name;
});
var editLat = document.createElement("input")
editLat.type = "text"
editLat.value = d.lat.toFixed(9)
el.appendChild(createBox("lat", "Breitengrad", editLat))
var editLat = document.createElement("input");
editLat.type = "text";
editLat.value = d.lat.toFixed(9);
el.appendChild(createBox("lat", "Breitengrad", editLat));
var editLng = document.createElement("input")
editLng.type = "text"
editLng.value = d.lng.toFixed(9)
el.appendChild(createBox("lng", "Längengrad", editLng))
var editLng = document.createElement("input");
editLng.type = "text";
editLng.value = d.lng.toFixed(9);
el.appendChild(createBox("lng", "Längengrad", editLng));
var editUci = document.createElement("textarea")
var editUci = document.createElement("textarea");
editUci.value =
"uci set gluon-node-info.@location[0]='location'; " +
"uci set gluon-node-info.@location[0].share_location='1';" +
"uci set gluon-node-info.@location[0].latitude='" + d.lat.toFixed(9) + "';" +
"uci set gluon-node-info.@location[0].longitude='" + d.lng.toFixed(9) + "';" +
"uci commit gluon-node-info"
"uci commit gluon-node-info";
el.appendChild(createBox("uci", "Befehl", editUci, false))
el.appendChild(createBox("uci", "Befehl", editUci, false));
var linkPlain = document.createElement("a")
linkPlain.textContent = "plain"
var linkPlain = document.createElement("a");
linkPlain.textContent = "plain";
linkPlain.onclick = function() {
switch2plain()
return false
}
linkPlain.href = "#"
switch2plain();
return false;
};
linkPlain.href = "#";
var linkUci = document.createElement("a")
linkUci.textContent = "uci"
var linkUci = document.createElement("a");
linkUci.textContent = "uci";
linkUci.onclick = function() {
switch2uci()
return false
}
linkUci.href = "#"
switch2uci();
return false;
};
linkUci.href = "#";
var hintText = document.createElement("p")
hintText.appendChild(document.createTextNode("Du kannst zwischen "))
hintText.appendChild(linkPlain)
hintText.appendChild(document.createTextNode(" und "))
hintText.appendChild(linkUci)
hintText.appendChild(document.createTextNode(" wechseln."))
el.appendChild(hintText)
var hintText = document.createElement("p");
hintText.appendChild(document.createTextNode("Du kannst zwischen "));
hintText.appendChild(linkPlain);
hintText.appendChild(document.createTextNode(" und "));
hintText.appendChild(linkUci);
hintText.appendChild(document.createTextNode(" wechseln."));
el.appendChild(hintText);
function createBox(name, title, inputElem, isVisible) {
var visible = typeof isVisible !== "undefined" ? isVisible : true
var box = document.createElement("div")
var heading = document.createElement("h3")
heading.textContent = title
box.appendChild(heading)
var btn = document.createElement("button")
btn.className = "ion-ios-copy"
btn.title = "Kopieren"
btn.onclick = function() { copy2clip(inputElem.id) }
inputElem.id = "location-" + name
inputElem.readOnly = true
var line = document.createElement("p")
line.appendChild(inputElem)
line.appendChild(btn)
box.appendChild(line)
box.id = "box-" + name
box.style.display = visible ? "block" : "none"
return box
var visible = typeof isVisible !== "undefined" ? isVisible : true;
var box = document.createElement("div");
var heading = document.createElement("h3");
heading.textContent = title;
box.appendChild(heading);
var btn = document.createElement("button");
btn.className = "ion-ios-copy";
btn.title = "Kopieren";
btn.onclick = function() { copy2clip(inputElem.id); };
inputElem.id = "location-" + name;
inputElem.readOnly = true;
var line = document.createElement("p");
line.appendChild(inputElem);
line.appendChild(btn);
box.appendChild(line);
box.id = "box-" + name;
box.style.display = visible ? "block" : "none";
return box;
}
function copy2clip(id) {
var copyField = document.querySelector("#" + id)
copyField.select()
var copyField = document.querySelector("#" + id);
copyField.select();
try {
document.execCommand("copy")
document.execCommand("copy");
} catch (err) {
console.log(err)
console.log(err);
}
}
function switch2plain() {
document.getElementById("box-uci").style.display = "none"
document.getElementById("box-lat").style.display = "block"
document.getElementById("box-lng").style.display = "block"
document.getElementById("box-uci").style.display = "none";
document.getElementById("box-lat").style.display = "block";
document.getElementById("box-lng").style.display = "block";
}
function switch2uci() {
document.getElementById("box-uci").style.display = "block"
document.getElementById("box-lat").style.display = "none"
document.getElementById("box-lng").style.display = "none"
document.getElementById("box-uci").style.display = "block";
document.getElementById("box-lat").style.display = "none";
document.getElementById("box-lng").style.display = "none";
}
}
})
};
});

View File

@ -1,51 +1,51 @@
define(["infobox/link", "infobox/node", "infobox/location"], function (Link, Node, Location) {
return function (config, sidebar, router) {
var self = this
var el
var self = this;
var el;
function destroy() {
if (el && el.parentNode) {
el.parentNode.removeChild(el)
el = undefined
sidebar.reveal()
el.parentNode.removeChild(el);
el = undefined;
sidebar.reveal();
}
}
function create() {
destroy()
sidebar.ensureVisible()
sidebar.hide()
destroy();
sidebar.ensureVisible();
sidebar.hide();
el = document.createElement("div")
sidebar.container.insertBefore(el, sidebar.container.firstChild)
el = document.createElement("div");
sidebar.container.insertBefore(el, sidebar.container.firstChild);
el.scrollIntoView(false)
el.classList.add("infobox")
el.destroy = destroy
el.scrollIntoView(false);
el.classList.add("infobox");
el.destroy = destroy;
var closeButton = document.createElement("button")
closeButton.classList.add("close")
closeButton.onclick = router.reset
el.appendChild(closeButton)
var closeButton = document.createElement("button");
closeButton.classList.add("close");
closeButton.onclick = router.reset;
el.appendChild(closeButton);
}
self.resetView = destroy
self.resetView = destroy;
self.gotoNode = function (d) {
create()
new Node(config, el, router, d)
}
create();
new Node(config, el, router, d);
};
self.gotoLink = function (d) {
create()
new Link(config, el, router, d)
}
create();
new Link(config, el, router, d);
};
self.gotoLocation = function (d) {
create()
new Location(config, el, router, d)
}
create();
new Location(config, el, router, d);
};
return self
}
})
return self;
};
});

View File

@ -2,366 +2,366 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
function (moment, numeral, Tablesort) {
function showGeoURI(d) {
function showLatitude(d) {
var suffix = Math.sign(d) > -1 ? "'N" : "'S"
d = Math.abs(d)
var a = Math.floor(d)
var min = (d * 60) % 60
a = (a < 10 ? "0" : "") + a
var suffix = Math.sign(d) > -1 ? "'N" : "'S";
d = Math.abs(d);
var a = Math.floor(d);
var min = (d * 60) % 60;
a = (a < 10 ? "0" : "") + a;
return a + "° " + numeral(min).format("0.000") + suffix
return a + "° " + numeral(min).format("0.000") + suffix;
}
function showLongitude(d) {
var suffix = Math.sign(d) > -1 ? "'E" : "'W"
d = Math.abs(d)
var a = Math.floor(d)
var min = (d * 60) % 60
a = (a < 100 ? "0" + (a < 10 ? "0" : "") : "") + a
var suffix = Math.sign(d) > -1 ? "'E" : "'W";
d = Math.abs(d);
var a = Math.floor(d);
var min = (d * 60) % 60;
a = (a < 100 ? "0" + (a < 10 ? "0" : "") : "") + a;
return a + "° " + numeral(min).format("0.000") + suffix
return a + "° " + numeral(min).format("0.000") + suffix;
}
if (!has_location(d))
return undefined
return undefined;
return function (el) {
var latitude = d.nodeinfo.location.latitude
var longitude = d.nodeinfo.location.longitude
var a = document.createElement("a")
var latitude = d.nodeinfo.location.latitude;
var longitude = d.nodeinfo.location.longitude;
var a = document.createElement("a");
a.textContent = showLatitude(latitude) + " " +
showLongitude(longitude)
showLongitude(longitude);
a.href = "geo:" + latitude + "," + longitude
el.appendChild(a)
}
a.href = "geo:" + latitude + "," + longitude;
el.appendChild(a);
};
}
function showStatus(d) {
return function (el) {
el.classList.add(d.flags.unseen ? "unseen" : (d.flags.online ? "online" : "offline"))
el.classList.add(d.flags.unseen ? "unseen" : (d.flags.online ? "online" : "offline"));
if (d.flags.online)
el.textContent = "online, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")"
el.textContent = "online, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")";
else
el.textContent = "offline, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")"
}
el.textContent = "offline, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY, H:mm:ss") + ")";
};
}
function showFirmware(d) {
var release = dictGet(d.nodeinfo, ["software", "firmware", "release"])
var base = dictGet(d.nodeinfo, ["software", "firmware", "base"])
var release = dictGet(d.nodeinfo, ["software", "firmware", "release"]);
var base = dictGet(d.nodeinfo, ["software", "firmware", "base"]);
if (release === null || base === null)
return undefined
return undefined;
return release + " / " + base
return release + " / " + base;
}
function showSite(d, config) {
var site = dictGet(d.nodeinfo, ["system", "site_code"])
var rt = site
var site = dictGet(d.nodeinfo, ["system", "site_code"]);
var rt = site;
if (config.siteNames)
config.siteNames.forEach( function (t) {
if(site === t.site)
rt = t.name
})
return rt
rt = t.name;
});
return rt;
}
function showUptime(d) {
if (!("uptime" in d.statistics))
return undefined
return undefined;
return moment.duration(d.statistics.uptime, "seconds").humanize()
return moment.duration(d.statistics.uptime, "seconds").humanize();
}
function showFirstseen(d) {
if (!("firstseen" in d))
return undefined
return undefined;
return d.firstseen.fromNow(true)
return d.firstseen.fromNow(true);
}
function showClients(d) {
if (!d.flags.online)
return undefined
return undefined;
return function (el) {
el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"))
el.appendChild(document.createElement("br"))
el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"));
el.appendChild(document.createElement("br"));
var span = document.createElement("span")
span.classList.add("clients")
span.textContent = " ".repeat(d.statistics.clients)
el.appendChild(span)
}
var span = document.createElement("span");
span.classList.add("clients");
span.textContent = " ".repeat(d.statistics.clients);
el.appendChild(span);
};
}
function showIPs(d) {
var ips = dictGet(d.nodeinfo, ["network", "addresses"])
var ips = dictGet(d.nodeinfo, ["network", "addresses"]);
if (ips === null)
return undefined
return undefined;
ips.sort()
ips.sort();
return function (el) {
ips.forEach( function (ip, i) {
var link = !ip.startsWith("fe80:")
var link = !ip.startsWith("fe80:");
if (i > 0)
el.appendChild(document.createElement("br"))
el.appendChild(document.createElement("br"));
if (link) {
var a = document.createElement("a")
a.href = "http://[" + ip + "]/"
a.textContent = ip
el.appendChild(a)
var a = document.createElement("a");
a.href = "http://[" + ip + "]/";
a.textContent = ip;
el.appendChild(a);
} else
el.appendChild(document.createTextNode(ip))
})
}
el.appendChild(document.createTextNode(ip));
});
};
}
function showBar(className, v) {
var span = document.createElement("span")
span.classList.add("bar")
span.classList.add(className)
var span = document.createElement("span");
span.classList.add("bar");
span.classList.add(className);
var bar = document.createElement("span")
bar.style.width = (v * 100) + "%"
span.appendChild(bar)
var bar = document.createElement("span");
bar.style.width = (v * 100) + "%";
span.appendChild(bar);
var label = document.createElement("label")
label.textContent = (Math.round(v * 100)) + " %"
span.appendChild(label)
var label = document.createElement("label");
label.textContent = (Math.round(v * 100)) + " %";
span.appendChild(label);
return span
return span;
}
function showLoadBar(className, v) {
var span = document.createElement("span")
span.classList.add("bar")
span.classList.add(className)
var span = document.createElement("span");
span.classList.add("bar");
span.classList.add(className);
var bar = document.createElement("span")
var bar = document.createElement("span");
if (v >= 1) {
bar.style.width = ((v * 100) % 100) + "%"
bar.style.background = "rgba(255, 50, 50, 0.9)"
span.style.background = "rgba(255, 50, 50, 0.6)"
span.appendChild(bar)
bar.style.width = ((v * 100) % 100) + "%";
bar.style.background = "rgba(255, 50, 50, 0.9)";
span.style.background = "rgba(255, 50, 50, 0.6)";
span.appendChild(bar);
}
else
{
bar.style.width = (v * 100) + "%"
span.appendChild(bar)
bar.style.width = (v * 100) + "%";
span.appendChild(bar);
}
var label = document.createElement("label")
label.textContent = (v)
span.appendChild(label)
var label = document.createElement("label");
label.textContent = (v);
span.appendChild(label);
return span
return span;
}
function showLoad(d) {
if (!("loadavg" in d.statistics))
return undefined
return undefined;
return function (el) {
el.appendChild(showLoadBar("load-avg", d.statistics.loadavg))
}
el.appendChild(showLoadBar("load-avg", d.statistics.loadavg));
};
}
function showRAM(d) {
if (!("memory_usage" in d.statistics))
return undefined
return undefined;
return function (el) {
el.appendChild(showBar("memory-usage", d.statistics.memory_usage))
}
el.appendChild(showBar("memory-usage", d.statistics.memory_usage));
};
}
function showPages(d) {
var webpages = dictGet(d.nodeinfo, ["pages"])
var webpages = dictGet(d.nodeinfo, ["pages"]);
if (webpages === null)
return undefined
return undefined;
webpages.sort()
webpages.sort();
return function (el) {
webpages.forEach( function (webpage, i) {
if (i > 0)
el.appendChild(document.createElement("br"))
el.appendChild(document.createElement("br"));
var a = document.createElement("span")
var link = document.createElement("a")
link.href = webpage
var a = document.createElement("span");
var link = document.createElement("a");
link.href = webpage;
if (webpage.search(/^https:\/\//i) !== -1) {
var lock = document.createElement("span")
lock.className = "ion-android-lock"
a.appendChild(lock)
var t1 = document.createTextNode(" ")
a.appendChild(t1)
link.textContent = webpage.replace(/^https:\/\//i, "")
var lock = document.createElement("span");
lock.className = "ion-android-lock";
a.appendChild(lock);
var t1 = document.createTextNode(" ");
a.appendChild(t1);
link.textContent = webpage.replace(/^https:\/\//i, "");
}
else
link.textContent = webpage.replace(/^http:\/\//i, "")
a.appendChild(link)
el.appendChild(a)
})
}
link.textContent = webpage.replace(/^http:\/\//i, "");
a.appendChild(link);
el.appendChild(a);
});
};
}
function showAutoupdate(d) {
var au = dictGet(d.nodeinfo, ["software", "autoupdater"])
var au = dictGet(d.nodeinfo, ["software", "autoupdater"]);
if (!au)
return undefined
return undefined;
return au.enabled ? "aktiviert (" + au.branch + ")" : "deaktiviert"
return au.enabled ? "aktiviert (" + au.branch + ")" : "deaktiviert";
}
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 : "unknown"
return showStat(o, subst)
var subst = {};
subst["{NODE_ID}"] = d.nodeinfo.node_id ? d.nodeinfo.node_id : "unknown";
subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname : "unknown";
return showStat(o, subst);
}
return function(config, el, router, d) {
var h2 = document.createElement("h2")
h2.textContent = d.nodeinfo.hostname
el.appendChild(h2)
var h2 = document.createElement("h2");
h2.textContent = d.nodeinfo.hostname;
el.appendChild(h2);
var attributes = document.createElement("table")
attributes.classList.add("attributes")
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))
attributeEntry(attributes, "Status", showStatus(d));
attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null);
attributeEntry(attributes, "Koordinaten", showGeoURI(d));
if (config.showContact)
attributeEntry(attributes, "Kontakt", dictGet(d.nodeinfo, ["owner", "contact"]))
attributeEntry(attributes, "Kontakt", 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))
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));
el.appendChild(attributes)
el.appendChild(attributes);
if (config.nodeInfos)
config.nodeInfos.forEach( function (nodeInfo) {
var h4 = document.createElement("h4")
h4.textContent = nodeInfo.name
el.appendChild(h4)
el.appendChild(showStatImg(nodeInfo, d))
})
var h4 = document.createElement("h4");
h4.textContent = nodeInfo.name;
el.appendChild(h4);
el.appendChild(showStatImg(nodeInfo, d));
});
if (d.neighbours.length > 0) {
var h3 = document.createElement("h3")
h3.textContent = "Links (" + d.neighbours.length + ")"
el.appendChild(h3)
var h3 = document.createElement("h3");
h3.textContent = "Links (" + d.neighbours.length + ")";
el.appendChild(h3);
var table = document.createElement("table")
var thead = document.createElement("thead")
var table = document.createElement("table");
var thead = document.createElement("thead");
var tr = document.createElement("tr")
var th1 = document.createElement("th")
th1.textContent = " "
tr.appendChild(th1)
var tr = document.createElement("tr");
var th1 = document.createElement("th");
th1.textContent = " ";
tr.appendChild(th1);
var th2 = document.createElement("th")
th2.textContent = "Knoten"
th2.classList.add("sort-default")
tr.appendChild(th2)
var th2 = document.createElement("th");
th2.textContent = "Knoten";
th2.classList.add("sort-default");
tr.appendChild(th2);
var th3 = document.createElement("th")
th3.textContent = "TQ"
tr.appendChild(th3)
var th3 = document.createElement("th");
th3.textContent = "TQ";
tr.appendChild(th3);
var th4 = document.createElement("th")
th4.textContent = "Typ"
tr.appendChild(th4)
var th4 = document.createElement("th");
th4.textContent = "Typ";
tr.appendChild(th4);
var th5 = document.createElement("th")
th5.textContent = "Entfernung"
tr.appendChild(th5)
var th5 = document.createElement("th");
th5.textContent = "Entfernung";
tr.appendChild(th5);
thead.appendChild(tr)
table.appendChild(thead)
thead.appendChild(tr);
table.appendChild(thead);
var tbody = document.createElement("tbody")
var tbody = document.createElement("tbody");
d.neighbours.forEach( function (d) {
var unknown = !(d.node)
var tr = document.createElement("tr")
var unknown = !(d.node);
var tr = document.createElement("tr");
var td1 = document.createElement("td")
td1.appendChild(document.createTextNode(d.incoming ? " ← " : " → "))
tr.appendChild(td1)
var td1 = document.createElement("td");
td1.appendChild(document.createTextNode(d.incoming ? " ← " : " → "));
tr.appendChild(td1);
var td2 = document.createElement("td")
var a1 = document.createElement("a")
a1.classList.add("hostname")
a1.textContent = unknown ? d.id : d.node.nodeinfo.hostname
var td2 = document.createElement("td");
var a1 = document.createElement("a");
a1.classList.add("hostname");
a1.textContent = unknown ? d.id : d.node.nodeinfo.hostname;
if (!unknown)
a1.href = "#"
a1.onclick = router.node(d.node)
td2.appendChild(a1)
a1.href = "#";
a1.onclick = router.node(d.node);
td2.appendChild(a1);
if (!unknown && has_location(d.node)) {
var span = document.createElement("span")
span.classList.add("icon")
span.classList.add("ion-location")
td2.appendChild(span)
var span = document.createElement("span");
span.classList.add("icon");
span.classList.add("ion-location");
td2.appendChild(span);
}
tr.appendChild(td2)
tr.appendChild(td2);
var td3 = document.createElement("td")
var a2 = document.createElement("a")
a2.href = "#"
a2.textContent = showTq(d.link)
a2.onclick = router.link(d.link)
td3.appendChild(a2)
tr.appendChild(td3)
var td3 = document.createElement("td");
var a2 = document.createElement("a");
a2.href = "#";
a2.textContent = showTq(d.link);
a2.onclick = router.link(d.link);
td3.appendChild(a2);
tr.appendChild(td3);
var td4 = document.createElement("td")
var a3 = document.createElement("a")
a3.href = "#"
a3.textContent = d.link.type
a3.onclick = router.link(d.link)
td4.appendChild(a3)
tr.appendChild(td4)
var td4 = document.createElement("td");
var a3 = document.createElement("a");
a3.href = "#";
a3.textContent = d.link.type;
a3.onclick = router.link(d.link);
td4.appendChild(a3);
tr.appendChild(td4);
var td5 = document.createElement("td")
var a4 = document.createElement("a")
a4.href = "#"
a4.textContent = showDistance(d.link)
a4.onclick = router.link(d.link)
td5.appendChild(a4)
td5.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1)
tr.appendChild(td5)
var td5 = document.createElement("td");
var a4 = document.createElement("a");
a4.href = "#";
a4.textContent = showDistance(d.link);
a4.onclick = router.link(d.link);
td5.appendChild(a4);
td5.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1);
tr.appendChild(td5);
tbody.appendChild(tr)
})
tbody.appendChild(tr);
});
table.appendChild(tbody)
table.className = "node-links"
table.appendChild(tbody);
table.className = "node-links";
new Tablesort(table)
new Tablesort(table);
el.appendChild(table)
el.appendChild(table);
}
}
})
};
});

View File

@ -1,41 +1,41 @@
define(function () {
return function () {
var self = this
var self = this;
self.render = function (el) {
var p = document.createElement("p")
p.setAttribute("class", "legend")
el.appendChild(p)
var p = document.createElement("p");
p.setAttribute("class", "legend");
el.appendChild(p);
var spanNew = document.createElement("span")
spanNew.setAttribute("class", "legend-new")
var symbolNew = document.createElement("span")
symbolNew.setAttribute("class", "symbol")
var textNew = document.createTextNode(" Neuer Knoten")
spanNew.appendChild(symbolNew)
spanNew.appendChild(textNew)
p.appendChild(spanNew)
var spanNew = document.createElement("span");
spanNew.setAttribute("class", "legend-new");
var symbolNew = document.createElement("span");
symbolNew.setAttribute("class", "symbol");
var textNew = document.createTextNode(" Neuer Knoten");
spanNew.appendChild(symbolNew);
spanNew.appendChild(textNew);
p.appendChild(spanNew);
var spanOnline = document.createElement("span")
spanOnline.setAttribute("class", "legend-online")
var symbolOnline = document.createElement("span")
symbolOnline.setAttribute("class", "symbol")
var textOnline = document.createTextNode(" Knoten ist online")
spanOnline.appendChild(symbolOnline)
spanOnline.appendChild(textOnline)
p.appendChild(spanOnline)
var spanOnline = document.createElement("span");
spanOnline.setAttribute("class", "legend-online");
var symbolOnline = document.createElement("span");
symbolOnline.setAttribute("class", "symbol");
var textOnline = document.createTextNode(" Knoten ist online");
spanOnline.appendChild(symbolOnline);
spanOnline.appendChild(textOnline);
p.appendChild(spanOnline);
var spanOffline = document.createElement("span")
spanOffline.setAttribute("class", "legend-offline")
var symbolOffline = document.createElement("span")
symbolOffline.setAttribute("class", "symbol")
var textOffline = document.createTextNode(" Knoten ist offline")
spanOffline.appendChild(symbolOffline)
spanOffline.appendChild(textOffline)
p.appendChild(spanOffline)
}
var spanOffline = document.createElement("span");
spanOffline.setAttribute("class", "legend-offline");
var symbolOffline = document.createElement("span");
symbolOffline.setAttribute("class", "symbol");
var textOffline = document.createTextNode(" Knoten ist offline");
spanOffline.appendChild(symbolOffline);
spanOffline.appendChild(textOffline);
p.appendChild(spanOffline);
};
return self
}
})
return self;
};
});

View File

@ -1,60 +1,60 @@
define(["sorttable", "virtual-dom"], function (SortTable, V) {
function linkName(d) {
return (d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " " + d.target.node.nodeinfo.hostname
return (d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " " + d.target.node.nodeinfo.hostname;
}
var headings = [{ name: "Knoten",
sort: function (a, b) {
return linkName(a).localeCompare(linkName(b))
return linkName(a).localeCompare(linkName(b));
},
reverse: false
},
{ name: "TQ",
sort: function (a, b) { return a.tq - b.tq},
sort: function (a, b) { return a.tq - b.tq; },
reverse: true
},
{ name: "Typ",
sort: function (a, b) {
return a.type.localeCompare(b.type)
return a.type.localeCompare(b.type);
},
reverse: false
},
{ name: "Entfernung",
sort: function (a, b) {
return (a.distance === undefined ? -1 : a.distance) -
(b.distance === undefined ? -1 : b.distance)
(b.distance === undefined ? -1 : b.distance);
},
reverse: true
}]
}];
return function(linkScale, router) {
var table = new SortTable(headings, 2, renderRow)
var table = new SortTable(headings, 2, renderRow);
function renderRow(d) {
var td1Content = [V.h("a", {href: "#", onclick: router.link(d)}, linkName(d))]
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", d.type)
var td4 = V.h("td", showDistance(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", d.type);
var td4 = V.h("td", showDistance(d));
return V.h("tr", [td1, td2, td3, td4])
return V.h("tr", [td1, td2, td3, td4]);
}
this.render = function (d) {
var el = document.createElement("div")
el.last = V.h("div")
d.appendChild(el)
var el = document.createElement("div");
el.last = V.h("div");
d.appendChild(el);
var h2 = document.createElement("h2")
h2.textContent = "Verbindungen"
el.appendChild(h2)
var h2 = document.createElement("h2");
h2.textContent = "Verbindungen";
el.appendChild(h2);
el.appendChild(table.el)
}
el.appendChild(table.el);
};
this.setData = function (d) {
table.setData(d.graph.links)
}
}
})
table.setData(d.graph.links);
};
};
});

View File

@ -30,30 +30,30 @@ define(["leaflet"], function (L) {
},
initialize: function(latlng) {
this.accuracyCircle = L.circle(latlng, 0, this.accuracyCircle)
this.outerCircle = L.circleMarker(latlng, this.outerCircle)
L.CircleMarker.prototype.initialize.call(this, latlng, this.innerCircle)
this.accuracyCircle = L.circle(latlng, 0, this.accuracyCircle);
this.outerCircle = L.circleMarker(latlng, this.outerCircle);
L.CircleMarker.prototype.initialize.call(this, latlng, this.innerCircle);
this.on("remove", function() {
this._map.removeLayer(this.accuracyCircle)
this._map.removeLayer(this.outerCircle)
})
this._map.removeLayer(this.accuracyCircle);
this._map.removeLayer(this.outerCircle);
});
},
setLatLng: function(latlng) {
this.accuracyCircle.setLatLng(latlng)
this.outerCircle.setLatLng(latlng)
L.CircleMarker.prototype.setLatLng.call(this, latlng)
this.accuracyCircle.setLatLng(latlng);
this.outerCircle.setLatLng(latlng);
L.CircleMarker.prototype.setLatLng.call(this, latlng);
},
setAccuracy: function(accuracy) {
this.accuracyCircle.setRadius(accuracy)
this.accuracyCircle.setRadius(accuracy);
},
onAdd: function(map) {
this.accuracyCircle.addTo(map).bringToBack()
this.outerCircle.addTo(map)
L.CircleMarker.prototype.onAdd.call(this, map)
this.accuracyCircle.addTo(map).bringToBack();
this.outerCircle.addTo(map);
L.CircleMarker.prototype.onAdd.call(this, map);
}
})
})
});
});

View File

@ -2,95 +2,95 @@ define(["moment", "router", "leaflet", "gui", "numeral"],
function (moment, Router, L, GUI, numeral) {
return function (config) {
function handleData(data) {
var dataNodes = {}
dataNodes.nodes = []
var dataGraph = {}
dataGraph.batadv = {}
dataGraph.batadv.nodes = []
dataGraph.batadv.links = []
var dataNodes = {};
dataNodes.nodes = [];
var dataGraph = {};
dataGraph.batadv = {};
dataGraph.batadv.nodes = [];
dataGraph.batadv.links = [];
function rearrangeLinks(d) {
d.source += dataGraph.batadv.nodes.length
d.target += dataGraph.batadv.nodes.length
d.source += dataGraph.batadv.nodes.length;
d.target += dataGraph.batadv.nodes.length;
}
for (var i = 0; i < data.length; ++i) {
var vererr
var vererr;
if(i % 2)
if (data[i].version !== 1) {
vererr = "Unsupported graph version: " + data[i].version
console.log(vererr) //silent fail
vererr = "Unsupported graph version: " + data[i].version;
console.log(vererr); //silent fail
} else {
data[i].batadv.links.forEach(rearrangeLinks)
dataGraph.batadv.nodes = dataGraph.batadv.nodes.concat(data[i].batadv.nodes)
dataGraph.batadv.links = dataGraph.batadv.links.concat(data[i].batadv.links)
dataGraph.timestamp = data[i].timestamp
data[i].batadv.links.forEach(rearrangeLinks);
dataGraph.batadv.nodes = dataGraph.batadv.nodes.concat(data[i].batadv.nodes);
dataGraph.batadv.links = dataGraph.batadv.links.concat(data[i].batadv.links);
dataGraph.timestamp = data[i].timestamp;
}
else
if (data[i].version !== 2) {
vererr = "Unsupported nodes version: " + data[i].version
console.log(vererr) //silent fail
vererr = "Unsupported nodes version: " + data[i].version;
console.log(vererr); //silent fail
} else {
dataNodes.nodes = dataNodes.nodes.concat(data[i].nodes)
dataNodes.timestamp = data[i].timestamp
dataNodes.nodes = dataNodes.nodes.concat(data[i].nodes);
dataNodes.timestamp = data[i].timestamp;
}
}
var nodes = dataNodes.nodes.filter( function (d) {
return "firstseen" in d && "lastseen" in d
})
return "firstseen" in d && "lastseen" in d;
});
nodes.forEach( function(node) {
node.firstseen = moment.utc(node.firstseen).local()
node.lastseen = moment.utc(node.lastseen).local()
})
node.firstseen = moment.utc(node.firstseen).local();
node.lastseen = moment.utc(node.lastseen).local();
});
var now = moment()
var age = moment(now).subtract(config.maxAge, "days")
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 = limit("firstseen", age, sortByKey("firstseen", nodes).filter(online));
var lostnodes = limit("lastseen", age, sortByKey("lastseen", nodes).filter(offline));
var graphnodes = {}
var graphnodes = {};
dataNodes.nodes.forEach( function (d) {
graphnodes[d.nodeinfo.node_id] = d
})
graphnodes[d.nodeinfo.node_id] = d;
});
var graph = dataGraph.batadv
var graph = dataGraph.batadv;
graph.nodes.forEach( function (d) {
if (d.node_id in graphnodes) {
d.node = graphnodes[d.node_id]
d.node = graphnodes[d.node_id];
if (d.unseen) {
d.node.flags.online = true
d.node.flags.unseen = true
d.node.flags.online = true;
d.node.flags.unseen = true;
}
}
})
});
graph.links.forEach( function (d) {
d.source = graph.nodes[d.source]
d.source = graph.nodes[d.source];
if (graph.nodes[d.target].node)
d.target = graph.nodes[d.target]
d.target = graph.nodes[d.target];
else
d.target = undefined
})
d.target = undefined;
});
var links = graph.links.filter( function (d) {
return d.target !== undefined
})
return d.target !== undefined;
});
links.forEach( function (d) {
var unknown = (d.source.node === undefined)
var ids
var unknown = (d.source.node === undefined);
var ids;
if (unknown)
ids = [d.source.id.replace(/:/g, ""), d.target.node.nodeinfo.node_id]
ids = [d.source.id.replace(/:/g, ""), d.target.node.nodeinfo.node_id];
else
ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id]
d.id = ids.join("-")
ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id];
d.id = ids.join("-");
if (unknown ||
!d.source.node.nodeinfo.location ||
@ -99,45 +99,45 @@ function (moment, Router, L, GUI, numeral) {
isNaN(d.source.node.nodeinfo.location.longitude) ||
isNaN(d.target.node.nodeinfo.location.latitude) ||
isNaN(d.target.node.nodeinfo.location.longitude))
return
return;
d.latlngs = []
d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude))
d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude))
d.latlngs = [];
d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude));
d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude));
d.distance = d.latlngs[0].distanceTo(d.latlngs[1])
})
d.distance = d.latlngs[0].distanceTo(d.latlngs[1]);
});
nodes.forEach( function (d) {
d.neighbours = []
})
d.neighbours = [];
});
links.forEach( function (d) {
if (d.type === "tunnel" || d.type === "fastd")
d.type = "fastd"
d.type = "fastd";
else if (d.type === "l2tp") {
d.type = "L2TP"
d.target.node.flags.uplink = true
d.type = "L2TP";
d.target.node.flags.uplink = true;
} else if (d.type === "wireless")
d.type = "Wifi"
d.type = "Wifi";
else if (d.type === "other")
d.type = "Kabel"
d.type = "Kabel";
else
d.type = "N/A"
var unknown = (d.source.node === undefined)
d.type = "N/A";
var unknown = (d.source.node === undefined);
if (unknown) {
d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true })
return
d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true });
return;
}
d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false })
d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true })
d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false });
d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true });
if (d.type !== "fastd" && d.type !== "L2TP")
d.source.node.meshlinks = d.source.node.meshlinks ? d.source.node.meshlinks + 1 : 1
})
d.source.node.meshlinks = d.source.node.meshlinks ? d.source.node.meshlinks + 1 : 1;
});
links.sort( function (a, b) {
return b.tq - a.tq
})
return b.tq - a.tq;
});
return { now: now,
timestamp: moment.utc(dataNodes.timestamp).local(),
@ -150,46 +150,46 @@ function (moment, Router, L, GUI, numeral) {
links: links,
nodes: graph.nodes
}
}
};
}
numeral.language("de")
moment.locale("de")
numeral.language("de");
moment.locale("de");
var router = new Router()
var router = new Router();
var urls = []
var urls = [];
if (typeof config.dataPath === "string" || config.dataPath instanceof String)
config.dataPath = [config.dataPath]
config.dataPath = [config.dataPath];
for (var i in config.dataPath) {
urls.push(config.dataPath[i] + "nodes.json")
urls.push(config.dataPath[i] + "graph.json")
urls.push(config.dataPath[i] + "nodes.json");
urls.push(config.dataPath[i] + "graph.json");
}
function update() {
return Promise.all(urls.map(getJSON))
.then(handleData)
.then(handleData);
}
update()
.then(function (d) {
var gui = new GUI(config, router)
gui.setData(d)
router.setData(d)
router.start()
var gui = new GUI(config, router);
gui.setData(d);
router.setData(d);
router.start();
window.setInterval(function () {
update().then(function (d) {
gui.setData(d)
router.setData(d)
})
}, 60000)
gui.setData(d);
router.setData(d);
});
}, 60000);
})
.catch(function (e) {
document.body.textContent = e
console.log(e)
})
}
})
document.body.textContent = e;
console.log(e);
});
};
});

View File

@ -4,7 +4,7 @@ define(["map/clientlayer", "map/labelslayer",
function (ClientLayer, LabelsLayer, d3, L, moment, LocationMarker, rbush) {
var options = { worldCopyJump: true,
zoomControl: false
}
};
var AddLayerButton = L.Control.extend({
options: {
@ -12,24 +12,24 @@ define(["map/clientlayer", "map/labelslayer",
},
initialize: function (f, options) {
L.Util.setOptions(this, options)
this.f = f
L.Util.setOptions(this, options);
this.f = f;
},
onAdd: function () {
var button = L.DomUtil.create("button", "add-layer")
button.textContent = "\uF2C7"
var button = L.DomUtil.create("button", "add-layer");
button.textContent = "\uF2C7";
// L.DomEvent.disableClickPropagation(button)
// Click propagation isn't disabled as this causes problems with the
// location picking mode; instead propagation is stopped in onClick().
L.DomEvent.addListener(button, "click", this.f, this)
L.DomEvent.addListener(button, "click", this.f, this);
this.button = button
this.button = button;
return button
return button;
}
})
});
var LocateButton = L.Control.extend({
options: {
@ -40,35 +40,35 @@ define(["map/clientlayer", "map/labelslayer",
button: undefined,
initialize: function (f, options) {
L.Util.setOptions(this, options)
this.f = f
L.Util.setOptions(this, options);
this.f = f;
},
onAdd: function () {
var button = L.DomUtil.create("button", "locate-user")
button.textContent = "\uF2E9"
var button = L.DomUtil.create("button", "locate-user");
button.textContent = "\uF2E9";
L.DomEvent.disableClickPropagation(button)
L.DomEvent.addListener(button, "click", this.onClick, this)
L.DomEvent.disableClickPropagation(button);
L.DomEvent.addListener(button, "click", this.onClick, this);
this.button = button
this.button = button;
return button
return button;
},
update: function() {
this.button.classList.toggle("active", this.active)
this.button.classList.toggle("active", this.active);
},
set: function(v) {
this.active = v
this.update()
this.active = v;
this.update();
},
onClick: function () {
this.f(!this.active)
this.f(!this.active);
}
})
});
var CoordsPickerButton = L.Control.extend({
options: {
@ -79,470 +79,470 @@ define(["map/clientlayer", "map/labelslayer",
button: undefined,
initialize: function (f, options) {
L.Util.setOptions(this, options)
this.f = f
L.Util.setOptions(this, options);
this.f = f;
},
onAdd: function () {
var button = L.DomUtil.create("button", "coord-picker")
button.textContent = "\uF2A6"
var button = L.DomUtil.create("button", "coord-picker");
button.textContent = "\uF2A6";
// Click propagation isn't disabled as this causes problems with the
// location picking mode; instead propagation is stopped in onClick().
L.DomEvent.addListener(button, "click", this.onClick, this)
L.DomEvent.addListener(button, "click", this.onClick, this);
this.button = button
this.button = button;
return button
return button;
},
update: function() {
this.button.classList.toggle("active", this.active)
this.button.classList.toggle("active", this.active);
},
set: function(v) {
this.active = v
this.update()
this.active = v;
this.update();
},
onClick: function (e) {
L.DomEvent.stopPropagation(e)
this.f(!this.active)
L.DomEvent.stopPropagation(e);
this.f(!this.active);
}
})
});
function mkMarker(dict, iconFunc, router) {
return function (d) {
var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d))
var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d));
m.resetStyle = function () {
m.setStyle(iconFunc(d))
}
m.setStyle(iconFunc(d));
};
m.on("click", router.node(d))
m.bindLabel(d.nodeinfo.hostname)
m.on("click", router.node(d));
m.bindLabel(d.nodeinfo.hostname);
dict[d.nodeinfo.node_id] = m
dict[d.nodeinfo.node_id] = m;
return m
}
return m;
};
}
function addLinksToMap(dict, linkScale, graph, router) {
graph = graph.filter( function (d) {
return "distance" in d && d.type !== "VPN"
})
return "distance" in d && d.type !== "VPN";
});
var lines = graph.map( function (d) {
var opts = { color: d.type === "Kabel" ? "#50B0F0" : linkScale(d.tq).hex(),
weight: 4,
opacity: 0.5,
dashArray: "none"
}
};
var line = L.polyline(d.latlngs, opts)
var line = L.polyline(d.latlngs, opts);
line.resetStyle = function () {
line.setStyle(opts)
}
line.setStyle(opts);
};
line.bindLabel(d.source.node.nodeinfo.hostname + " " + d.target.node.nodeinfo.hostname + "<br><strong>" + showDistance(d) + " / " + showTq(d) + "</strong>")
line.on("click", router.link(d))
line.bindLabel(d.source.node.nodeinfo.hostname + " " + d.target.node.nodeinfo.hostname + "<br><strong>" + showDistance(d) + " / " + showTq(d) + "</strong>");
line.on("click", router.link(d));
dict[d.id] = line
dict[d.id] = line;
return line
})
return line;
});
return lines
return lines;
}
var iconOnline = { color: "#1566A9", fillColor: "#1566A9", radius: 6, fillOpacity: 0.5, opacity: 0.5, weight: 2, className: "stroke-first" }
var iconOffline = { color: "#D43E2A", fillColor: "#D43E2A", radius: 3, fillOpacity: 0.5, opacity: 0.5, weight: 1, className: "stroke-first" }
var iconLost = { color: "#D43E2A", fillColor: "#D43E2A", radius: 6, fillOpacity: 0.8, opacity: 0.8, weight: 1, className: "stroke-first" }
var iconAlert = { color: "#D43E2A", fillColor: "#D43E2A", radius: 6, fillOpacity: 0.8, opacity: 0.8, weight: 2, className: "stroke-first node-alert" }
var iconNew = { color: "#1566A9", fillColor: "#93E929", radius: 6, fillOpacity: 1.0, opacity: 0.5, weight: 2 }
var iconOnline = { color: "#1566A9", fillColor: "#1566A9", radius: 6, fillOpacity: 0.5, opacity: 0.5, weight: 2, className: "stroke-first" };
var iconOffline = { color: "#D43E2A", fillColor: "#D43E2A", radius: 3, fillOpacity: 0.5, opacity: 0.5, weight: 1, className: "stroke-first" };
var iconLost = { color: "#D43E2A", fillColor: "#D43E2A", radius: 6, fillOpacity: 0.8, opacity: 0.8, weight: 1, className: "stroke-first" };
var iconAlert = { color: "#D43E2A", fillColor: "#D43E2A", radius: 6, fillOpacity: 0.8, opacity: 0.8, weight: 2, className: "stroke-first node-alert" };
var iconNew = { color: "#1566A9", fillColor: "#93E929", radius: 6, fillOpacity: 1.0, opacity: 0.5, weight: 2 };
return function (config, linkScale, sidebar, router, buttons) {
var self = this
var barycenter
var groupOnline, groupOffline, groupNew, groupLost, groupLines
var savedView
var self = this;
var barycenter;
var groupOnline, groupOffline, groupNew, groupLost, groupLines;
var savedView;
var map, userLocation
var layerControl
var customLayers = {}
var baseLayers = {}
var map, userLocation;
var layerControl;
var customLayers = {};
var baseLayers = {};
var locateUserButton = new LocateButton(function (d) {
if (d)
enableTracking()
enableTracking();
else
disableTracking()
})
disableTracking();
});
var mybuttons = []
var mybuttons = [];
function addButton(button) {
var el = button.onAdd()
mybuttons.push(el)
buttons.appendChild(el)
var el = button.onAdd();
mybuttons.push(el);
buttons.appendChild(el);
}
function clearButtons() {
mybuttons.forEach( function (d) {
buttons.removeChild(d)
})
buttons.removeChild(d);
});
}
var showCoordsPickerButton = new CoordsPickerButton(function (d) {
if (d)
enableCoords()
enableCoords();
else
disableCoords()
})
disableCoords();
});
function saveView() {
savedView = {center: map.getCenter(),
zoom: map.getZoom()}
zoom: map.getZoom()};
}
function enableTracking() {
map.locate({watch: true,
enableHighAccuracy: true,
setView: true
})
locateUserButton.set(true)
});
locateUserButton.set(true);
}
function disableTracking() {
map.stopLocate()
locationError()
locateUserButton.set(false)
map.stopLocate();
locationError();
locateUserButton.set(false);
}
function enableCoords() {
map.getContainer().classList.add("pick-coordinates")
map.on("click", showCoordinates)
showCoordsPickerButton.set(true)
map.getContainer().classList.add("pick-coordinates");
map.on("click", showCoordinates);
showCoordsPickerButton.set(true);
}
function disableCoords() {
map.getContainer().classList.remove("pick-coordinates")
map.off("click", showCoordinates)
showCoordsPickerButton.set(false)
map.getContainer().classList.remove("pick-coordinates");
map.off("click", showCoordinates);
showCoordsPickerButton.set(false);
}
function showCoordinates(e) {
router.gotoLocation(e.latlng)
router.gotoLocation(e.latlng);
// window.prompt("Koordinaten (Lat, Lng)", e.latlng.lat.toFixed(9) + ", " + e.latlng.lng.toFixed(9))
disableCoords()
disableCoords();
}
function locationFound(e) {
if (!userLocation)
userLocation = new LocationMarker(e.latlng).addTo(map)
userLocation = new LocationMarker(e.latlng).addTo(map);
userLocation.setLatLng(e.latlng)
userLocation.setAccuracy(e.accuracy)
userLocation.setLatLng(e.latlng);
userLocation.setAccuracy(e.accuracy);
}
function locationError() {
if (userLocation) {
map.removeLayer(userLocation)
userLocation = null
map.removeLayer(userLocation);
userLocation = null;
}
}
function addLayer(layerName) {
if (layerName in baseLayers)
return
return;
if (layerName in customLayers)
return
return;
try {
var layer = L.tileLayer.provider(layerName)
layerControl.addBaseLayer(layer, layerName)
customLayers[layerName] = layer
var layer = L.tileLayer.provider(layerName);
layerControl.addBaseLayer(layer, layerName);
customLayers[layerName] = layer;
if (localStorageTest())
localStorage.setItem("map/customLayers", JSON.stringify(Object.keys(customLayers)))
localStorage.setItem("map/customLayers", JSON.stringify(Object.keys(customLayers)));
} catch (e) {
return
console.log(e);
}
}
function contextMenuGotoLocation(e) {
router.gotoLocation(e.latlng)
router.gotoLocation(e.latlng);
}
var el = document.createElement("div")
el.classList.add("map")
var el = document.createElement("div");
el.classList.add("map");
map = L.map(el, options)
map = L.map(el, options);
var layers = config.mapLayers.map( function (d) {
return {
"name": d.name,
"layer": "url" in d ? L.tileLayer(d.url, d.config) : L.tileLayer.provider(d.name)
}
})
};
});
layers[0].layer.addTo(map)
layers[0].layer.addTo(map);
layers.forEach( function (d) {
baseLayers[d.name] = d.layer
})
baseLayers[d.name] = d.layer;
});
map.on("locationfound", locationFound)
map.on("locationerror", locationError)
map.on("dragend", saveView)
map.on("contextmenu", contextMenuGotoLocation)
map.on("locationfound", locationFound);
map.on("locationerror", locationError);
map.on("dragend", saveView);
map.on("contextmenu", contextMenuGotoLocation);
addButton(locateUserButton)
addButton(showCoordsPickerButton)
addButton(locateUserButton);
addButton(showCoordsPickerButton);
addButton(new AddLayerButton(function () {
/*eslint no-alert:0*/
var layerName = prompt("Leaflet Provider:")
addLayer(layerName)
}))
var layerName = prompt("Leaflet Provider:");
addLayer(layerName);
}));
layerControl = L.control.layers(baseLayers, [], {position: "bottomright"})
layerControl.addTo(map)
layerControl = L.control.layers(baseLayers, [], {position: "bottomright"});
layerControl.addTo(map);
if (localStorageTest()) {
var d = JSON.parse(localStorage.getItem("map/customLayers"))
var d = JSON.parse(localStorage.getItem("map/customLayers"));
if (d)
d.forEach(addLayer)
d.forEach(addLayer);
d = JSON.parse(localStorage.getItem("map/selectedLayer"))
d = d && d.name in baseLayers ? baseLayers[d.name] : d && d.name in customLayers ? customLayers[d.name] : false
d = JSON.parse(localStorage.getItem("map/selectedLayer"));
d = d && d.name in baseLayers ? baseLayers[d.name] : d && d.name in customLayers ? customLayers[d.name] : false;
if (d) {
map.removeLayer(layers[0].layer)
map.addLayer(d)
map.removeLayer(layers[0].layer);
map.addLayer(d);
}
}
var clientLayer = new ClientLayer({minZoom: 15})
clientLayer.addTo(map)
clientLayer.setZIndex(5)
var clientLayer = new ClientLayer({minZoom: 15});
clientLayer.addTo(map);
clientLayer.setZIndex(5);
var labelsLayer = new LabelsLayer({})
labelsLayer.addTo(map)
labelsLayer.setZIndex(6)
var labelsLayer = new LabelsLayer({});
labelsLayer.addTo(map);
labelsLayer.setZIndex(6);
map.on("baselayerchange", function(e) {
map.options.maxZoom = e.layer.options.maxZoom
clientLayer.options.maxZoom = map.options.maxZoom
labelsLayer.options.maxZoom = map.options.maxZoom
if (map.getZoom() > map.options.maxZoom) map.setZoom(map.options.maxZoom)
map.options.maxZoom = e.layer.options.maxZoom;
clientLayer.options.maxZoom = map.options.maxZoom;
labelsLayer.options.maxZoom = map.options.maxZoom;
if (map.getZoom() > map.options.maxZoom) map.setZoom(map.options.maxZoom);
if (localStorageTest())
localStorage.setItem("map/selectedLayer", JSON.stringify({name: e.name}))
})
localStorage.setItem("map/selectedLayer", JSON.stringify({name: e.name}));
});
var nodeDict = {}
var linkDict = {}
var highlight
var nodeDict = {};
var linkDict = {};
var highlight;
function resetMarkerStyles(nodes, links) {
Object.keys(nodes).forEach( function (d) {
nodes[d].resetStyle()
})
nodes[d].resetStyle();
});
Object.keys(links).forEach( function (d) {
links[d].resetStyle()
})
links[d].resetStyle();
});
}
function setView(bounds) {
map.fitBounds(bounds, {paddingTopLeft: [sidebar(), 0]})
map.fitBounds(bounds, {paddingTopLeft: [sidebar(), 0]});
}
function resetZoom() {
if (barycenter)
setView(barycenter.getBounds())
setView(barycenter.getBounds());
}
function goto(m) {
var bounds
var bounds;
if ("getBounds" in m)
bounds = m.getBounds()
bounds = m.getBounds();
else
bounds = L.latLngBounds([m.getLatLng()])
bounds = L.latLngBounds([m.getLatLng()]);
setView(bounds)
setView(bounds);
return m
return m;
}
function updateView(nopanzoom) {
resetMarkerStyles(nodeDict, linkDict)
var m
resetMarkerStyles(nodeDict, linkDict);
var m;
if (highlight !== undefined)
if (highlight.type === "node") {
m = nodeDict[highlight.o.nodeinfo.node_id]
m = nodeDict[highlight.o.nodeinfo.node_id];
if (m)
m.setStyle({ color: "orange", weight: 20, fillOpacity: 1, opacity: 0.7, className: "stroke-first" })
m.setStyle({ color: "orange", weight: 20, fillOpacity: 1, opacity: 0.7, className: "stroke-first" });
} else if (highlight.type === "link") {
m = linkDict[highlight.o.id]
m = linkDict[highlight.o.id];
if (m)
m.setStyle({ weight: 7, opacity: 1, dashArray: "10, 10" })
m.setStyle({ weight: 7, opacity: 1, dashArray: "10, 10" });
}
if (!nopanzoom)
if (m)
goto(m)
goto(m);
else if (savedView)
map.setView(savedView.center, savedView.zoom)
map.setView(savedView.center, savedView.zoom);
else
resetZoom()
resetZoom();
}
function calcBarycenter(nodes) {
nodes = nodes.map(function (d) { return d.nodeinfo.location })
nodes = nodes.map(function (d) { return d.nodeinfo.location; });
if (nodes.length === 0)
return undefined
return undefined;
var lats = nodes.map(function (d) { return d.latitude })
var lngs = nodes.map(function (d) { return d.longitude })
var lats = nodes.map(function (d) { return d.latitude; });
var lngs = nodes.map(function (d) { return d.longitude; });
var barycenter = L.latLng(d3.median(lats), d3.median(lngs))
var barycenterDev = [d3.deviation(lats), d3.deviation(lngs)]
var barycenter = L.latLng(d3.median(lats), d3.median(lngs));
var barycenterDev = [d3.deviation(lats), d3.deviation(lngs)];
if (barycenterDev[0] === undefined)
barycenterDev[0] = 0
barycenterDev[0] = 0;
if (barycenterDev[1] === undefined)
barycenterDev[1] = 0
barycenterDev[1] = 0;
var barycenterCircle = L.latLng(barycenter.lat + barycenterDev[0],
barycenter.lng + barycenterDev[1])
barycenter.lng + barycenterDev[1]);
var r = barycenter.distanceTo(barycenterCircle)
var r = barycenter.distanceTo(barycenterCircle);
return L.circle(barycenter, r * config.mapSigmaScale)
return L.circle(barycenter, r * config.mapSigmaScale);
}
function mapRTree(d) {
var o = [ d.nodeinfo.location.latitude, d.nodeinfo.location.longitude,
d.nodeinfo.location.latitude, d.nodeinfo.location.longitude]
d.nodeinfo.location.latitude, d.nodeinfo.location.longitude];
o.node = d
o.node = d;
return o
return o;
}
self.setData = function (data) {
nodeDict = {}
linkDict = {}
nodeDict = {};
linkDict = {};
if (groupOffline)
groupOffline.clearLayers()
groupOffline.clearLayers();
if (groupOnline)
groupOnline.clearLayers()
groupOnline.clearLayers();
if (groupNew)
groupNew.clearLayers()
groupNew.clearLayers();
if (groupLost)
groupLost.clearLayers()
groupLost.clearLayers();
if (groupLines)
groupLines.clearLayers()
groupLines.clearLayers();
var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router)
groupLines = L.featureGroup(lines).addTo(map)
var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router);
groupLines = L.featureGroup(lines).addTo(map);
if (typeof config.fixedCenter === "undefined")
barycenter = calcBarycenter(data.nodes.all.filter(has_location))
barycenter = calcBarycenter(data.nodes.all.filter(has_location));
else
barycenter = L.circle(L.latLng(new L.LatLng(config.fixedCenter.lat, config.fixedCenter.lng)), config.fixedCenter.radius * 1000)
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 = subtract(data.nodes.all.filter(online), data.nodes.new);
var nodesOffline = subtract(data.nodes.all.filter(offline), data.nodes.lost);
var markersOnline = nodesOnline.filter(has_location)
.map(mkMarker(nodeDict, function () { return iconOnline }, router))
.map(mkMarker(nodeDict, function () { return iconOnline; }, router));
var markersOffline = nodesOffline.filter(has_location)
.map(mkMarker(nodeDict, function () { return iconOffline }, router))
.map(mkMarker(nodeDict, function () { return iconOffline; }, router));
var markersNew = data.nodes.new.filter(has_location)
.map(mkMarker(nodeDict, function () { return iconNew }, router))
.map(mkMarker(nodeDict, function () { return iconNew; }, router));
var markersLost = data.nodes.lost.filter(has_location)
.map(mkMarker(nodeDict, function (d) {
if (d.lastseen.isAfter(moment(data.now).subtract(3, "days")))
return iconAlert
return iconAlert;
return iconLost
}, router))
return iconLost;
}, router));
groupOffline = L.featureGroup(markersOffline).addTo(map)
groupOnline = L.featureGroup(markersOnline).addTo(map)
groupLost = L.featureGroup(markersLost).addTo(map)
groupNew = L.featureGroup(markersNew).addTo(map)
groupOffline = L.featureGroup(markersOffline).addTo(map);
groupOnline = L.featureGroup(markersOnline).addTo(map);
groupLost = L.featureGroup(markersLost).addTo(map);
groupNew = L.featureGroup(markersNew).addTo(map);
var rtreeOnlineAll = rbush(9)
var rtreeOnlineAll = rbush(9);
rtreeOnlineAll.load(data.nodes.all.filter(online).filter(has_location).map(mapRTree))
rtreeOnlineAll.load(data.nodes.all.filter(online).filter(has_location).map(mapRTree));
clientLayer.setData(rtreeOnlineAll)
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)
})
});
updateView(true)
}
updateView(true);
};
self.resetView = function () {
disableTracking()
highlight = undefined
updateView()
}
disableTracking();
highlight = undefined;
updateView();
};
self.gotoNode = function (d) {
disableTracking()
highlight = {type: "node", o: d}
updateView()
}
disableTracking();
highlight = {type: "node", o: d};
updateView();
};
self.gotoLink = function (d) {
disableTracking()
highlight = {type: "link", o: d}
updateView()
}
disableTracking();
highlight = {type: "link", o: d};
updateView();
};
self.gotoLocation = function () {
//ignore
}
};
self.destroy = function () {
clearButtons()
map.remove()
clearButtons();
map.remove();
if (el.parentNode)
el.parentNode.removeChild(el)
}
el.parentNode.removeChild(el);
};
self.render = function (d) {
d.appendChild(el)
map.invalidateSize()
}
d.appendChild(el);
map.invalidateSize();
};
return self
}
})
return self;
};
});

View File

@ -1,76 +1,76 @@
define(["leaflet", "jshashes"],
function (L, jsHashes) {
var MD5 = new jsHashes.MD5()
var MD5 = new jsHashes.MD5();
return L.TileLayer.Canvas.extend({
setData: function (d) {
this.data = d
this.data = d;
//pre-calculate start angles
this.data.all().forEach(function (d) {
var hash = MD5.hex(d.node.nodeinfo.node_id)
d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI
})
this.redraw()
var hash = MD5.hex(d.node.nodeinfo.node_id);
d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI;
});
this.redraw();
},
drawTile: function (canvas, tilePoint) {
function getTileBBox(s, map, tileSize, margin) {
var tl = map.unproject([s.x - margin, s.y - margin])
var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize])
var tl = map.unproject([s.x - margin, s.y - margin]);
var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize]);
return [br.lat, tl.lng, tl.lat, br.lng]
return [br.lat, tl.lng, tl.lat, br.lng];
}
if (!this.data)
return
return;
var tileSize = this.options.tileSize
var s = tilePoint.multiplyBy(tileSize)
var map = this._map
var tileSize = this.options.tileSize;
var s = tilePoint.multiplyBy(tileSize);
var map = this._map;
var margin = 50
var bbox = getTileBBox(s, map, tileSize, margin)
var margin = 50;
var bbox = getTileBBox(s, map, tileSize, margin);
var nodes = this.data.search(bbox)
var nodes = this.data.search(bbox);
if (nodes.length === 0)
return
return;
var ctx = canvas.getContext("2d")
var ctx = canvas.getContext("2d");
var radius = 3
var a = 1.2
var startDistance = 12
var radius = 3;
var a = 1.2;
var startDistance = 12;
ctx.beginPath()
ctx.beginPath();
nodes.forEach(function (d) {
var p = map.project([d.node.nodeinfo.location.latitude, d.node.nodeinfo.location.longitude])
var clients = d.node.statistics.clients
var p = map.project([d.node.nodeinfo.location.latitude, d.node.nodeinfo.location.longitude]);
var clients = d.node.statistics.clients;
if (clients === 0)
return
return;
p.x -= s.x
p.y -= s.y
p.x -= s.x;
p.y -= s.y;
for (var orbit = 0, i = 0; i < clients; orbit++) {
var distance = startDistance + orbit * 2 * radius * a
var n = Math.floor((Math.PI * distance) / (a * radius))
var delta = clients - i
var distance = startDistance + orbit * 2 * radius * a;
var n = Math.floor((Math.PI * distance) / (a * radius));
var delta = clients - i;
for (var j = 0; j < Math.min(delta, n); i++, j++) {
var angle = 2 * Math.PI / n * j
var x = p.x + distance * Math.cos(angle + d.startAngle)
var y = p.y + distance * Math.sin(angle + d.startAngle)
var angle = 2 * Math.PI / n * j;
var x = p.x + distance * Math.cos(angle + d.startAngle);
var y = p.y + distance * Math.sin(angle + d.startAngle);
ctx.moveTo(x, y)
ctx.arc(x, y, radius, 0, 2 * Math.PI)
ctx.moveTo(x, y);
ctx.arc(x, y, radius, 0, 2 * Math.PI);
}
}
})
});
ctx.fillStyle = "rgba(220, 0, 103, 0.7)"
ctx.fill()
ctx.fillStyle = "rgba(220, 0, 103, 0.7)";
ctx.fill();
}
})
})
});
});

View File

@ -7,29 +7,29 @@ define(["leaflet", "rbush"],
["left", "ideographic", 1 / 8],
["right", "top", 5 / 8],
["center", "ideographic", 2 / 8],
["right", "ideographic", 3 / 8]]
["right", "ideographic", 3 / 8]];
var fontFamily = "Roboto"
var nodeRadius = 4
var fontFamily = "Roboto";
var nodeRadius = 4;
var ctx = document.createElement("canvas").getContext("2d")
var ctx = document.createElement("canvas").getContext("2d");
function measureText(font, text) {
ctx.font = font
return ctx.measureText(text)
ctx.font = font;
return ctx.measureText(text);
}
function mapRTree(d) {
var o = [d.position.lat, d.position.lng, d.position.lat, d.position.lng]
var o = [d.position.lat, d.position.lng, d.position.lat, d.position.lng];
o.label = d
o.label = d;
return o
return o;
}
function prepareLabel(fillStyle, fontSize, offset, stroke, minZoom) {
return function (d) {
var font = fontSize + "px " + fontFamily
var font = fontSize + "px " + fontFamily;
return { position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude),
label: d.nodeinfo.hostname,
offset: offset,
@ -39,50 +39,50 @@ define(["leaflet", "rbush"],
stroke: stroke,
minZoom: minZoom,
width: measureText(font, d.nodeinfo.hostname).width
}
}
};
};
}
function calcOffset(offset, loc) {
return [ offset * Math.cos(loc[2] * 2 * Math.PI),
-offset * Math.sin(loc[2] * 2 * Math.PI)]
-offset * Math.sin(loc[2] * 2 * Math.PI)];
}
function labelRect(p, offset, anchor, label, minZoom, maxZoom, z) {
var margin = 1 + 1.41 * (1 - (z - minZoom) / (maxZoom - minZoom))
var margin = 1 + 1.41 * (1 - (z - minZoom) / (maxZoom - minZoom));
var width = label.width * margin
var height = label.height * margin
var width = label.width * margin;
var height = label.height * margin;
var dx = { left: 0,
right: -width,
center: -width / 2
}
};
var dy = { top: 0,
ideographic: -height,
middle: -height / 2
}
};
var x = p.x + offset[0] + dx[anchor[0]]
var y = p.y + offset[1] + dy[anchor[1]]
var x = p.x + offset[0] + dx[anchor[0]];
var y = p.y + offset[1] + dy[anchor[1]];
return [x, y, x + width, y + height]
return [x, y, x + width, y + height];
}
var c = L.TileLayer.Canvas.extend({
onAdd: function (map) {
L.TileLayer.Canvas.prototype.onAdd.call(this, map)
L.TileLayer.Canvas.prototype.onAdd.call(this, map);
if (this.data)
this.prepareLabels()
this.prepareLabels();
},
setData: function (d) {
this.data = d
this.data = d;
if (this._map)
this.prepareLabels()
this.prepareLabels();
},
prepareLabels: function () {
var d = this.data
var d = this.data;
// label:
// - position (WGS84 coords)
@ -92,137 +92,137 @@ define(["leaflet", "rbush"],
// - label (string)
// - color (string)
var labelsOnline = d.online.map(prepareLabel("rgba(0, 0, 0, 0.9)", 10, 8, true, 13))
var labelsOffline = d.offline.map(prepareLabel("rgba(212, 62, 42, 0.9)", 9, 5, false, 16))
var labelsNew = d.new.map(prepareLabel("rgba(48, 99, 20, 0.9)", 11, 8, true, 0))
var labelsLost = d.lost.map(prepareLabel("rgba(212, 62, 42, 0.9)", 11, 8, true, 0))
var labelsOnline = d.online.map(prepareLabel("rgba(0, 0, 0, 0.9)", 10, 8, true, 13));
var labelsOffline = d.offline.map(prepareLabel("rgba(212, 62, 42, 0.9)", 9, 5, false, 16));
var labelsNew = d.new.map(prepareLabel("rgba(48, 99, 20, 0.9)", 11, 8, true, 0));
var labelsLost = d.lost.map(prepareLabel("rgba(212, 62, 42, 0.9)", 11, 8, true, 0));
var labels = []
.concat(labelsNew)
.concat(labelsLost)
.concat(labelsOnline)
.concat(labelsOffline)
.concat(labelsOffline);
var minZoom = this.options.minZoom
var maxZoom = this.options.maxZoom
var minZoom = this.options.minZoom;
var maxZoom = this.options.maxZoom;
var trees = []
var trees = [];
var map = this._map
var map = this._map;
function nodeToRect(z) {
return function (d) {
var p = map.project(d.position, z)
var p = map.project(d.position, z);
return [p.x - nodeRadius, p.y - nodeRadius,
p.x + nodeRadius, p.y + nodeRadius]
}
p.x + nodeRadius, p.y + nodeRadius];
};
}
for (var z = minZoom; z <= maxZoom; z++) {
trees[z] = rbush(9)
trees[z].load(labels.map(nodeToRect(z)))
trees[z] = rbush(9);
trees[z].load(labels.map(nodeToRect(z)));
}
labels = labels.map(function (d) {
var best = labelLocations.map(function (loc) {
var offset = calcOffset(d.offset, loc)
var z
var offset = calcOffset(d.offset, loc);
var z;
for (z = maxZoom; z >= d.minZoom; z--) {
var p = map.project(d.position, z)
var rect = labelRect(p, offset, loc, d, minZoom, maxZoom, z)
var candidates = trees[z].search(rect)
var p = map.project(d.position, z);
var rect = labelRect(p, offset, loc, d, minZoom, maxZoom, z);
var candidates = trees[z].search(rect);
if (candidates.length > 0)
break
break;
}
return {loc: loc, z: z + 1}
return {loc: loc, z: z + 1};
}).filter(function (d) {
return d.z <= maxZoom
return d.z <= maxZoom;
}).sort(function (a, b) {
return a.z - b.z
})[0]
return a.z - b.z;
})[0];
if (best !== undefined) {
d.offset = calcOffset(d.offset, best.loc)
d.minZoom = best.z
d.anchor = best.loc
d.offset = calcOffset(d.offset, best.loc);
d.minZoom = best.z;
d.anchor = best.loc;
for (var z = maxZoom; z >= best.z; z--) {
var p = map.project(d.position, z)
var rect = labelRect(p, d.offset, best.loc, d, minZoom, maxZoom, z)
trees[z].insert(rect)
var p = map.project(d.position, z);
var rect = labelRect(p, d.offset, best.loc, d, minZoom, maxZoom, z);
trees[z].insert(rect);
}
return d
return d;
} else
return undefined
}).filter(function (d) { return d !== undefined })
return undefined;
}).filter(function (d) { return d !== undefined; });
this.margin = 16
this.margin = 16;
if (labels.length > 0)
this.margin += labels.map(function (d) {
return d.width
}).sort().reverse()[0]
return d.width;
}).sort().reverse()[0];
this.labels = rbush(9)
this.labels.load(labels.map(mapRTree))
this.labels = rbush(9);
this.labels.load(labels.map(mapRTree));
this.redraw()
this.redraw();
},
drawTile: function (canvas, tilePoint, zoom) {
function getTileBBox(s, map, tileSize, margin) {
var tl = map.unproject([s.x - margin, s.y - margin])
var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize])
var tl = map.unproject([s.x - margin, s.y - margin]);
var br = map.unproject([s.x + margin + tileSize, s.y + margin + tileSize]);
return [br.lat, tl.lng, tl.lat, br.lng]
return [br.lat, tl.lng, tl.lat, br.lng];
}
if (!this.labels)
return
return;
var tileSize = this.options.tileSize
var s = tilePoint.multiplyBy(tileSize)
var map = this._map
var tileSize = this.options.tileSize;
var s = tilePoint.multiplyBy(tileSize);
var map = this._map;
function projectNodes(d) {
var p = map.project(d.label.position)
var p = map.project(d.label.position);
p.x -= s.x
p.y -= s.y
p.x -= s.x;
p.y -= s.y;
return {p: p, label: d.label}
return {p: p, label: d.label};
}
var bbox = getTileBBox(s, map, tileSize, this.margin)
var bbox = getTileBBox(s, map, tileSize, this.margin);
var labels = this.labels.search(bbox).map(projectNodes)
var labels = this.labels.search(bbox).map(projectNodes);
var ctx = canvas.getContext("2d")
var ctx = canvas.getContext("2d");
ctx.lineWidth = 5
ctx.strokeStyle = "rgba(255, 255, 255, 0.8)"
ctx.miterLimit = 2
ctx.lineWidth = 5;
ctx.strokeStyle = "rgba(255, 255, 255, 0.8)";
ctx.miterLimit = 2;
function drawLabel(d) {
ctx.font = d.label.font
ctx.textAlign = d.label.anchor[0]
ctx.textBaseline = d.label.anchor[1]
ctx.fillStyle = d.label.fillStyle
ctx.font = d.label.font;
ctx.textAlign = d.label.anchor[0];
ctx.textBaseline = d.label.anchor[1];
ctx.fillStyle = d.label.fillStyle;
if (d.label.stroke)
ctx.strokeText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])
ctx.strokeText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1]);
ctx.fillText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1])
ctx.fillText(d.label.label, d.p.x + d.label.offset[0], d.p.y + d.label.offset[1]);
}
labels.filter(function (d) {
return zoom >= d.label.minZoom
}).forEach(drawLabel)
return zoom >= d.label.minZoom;
}).forEach(drawLabel);
}
})
});
return c
})
return c;
});

View File

@ -1,49 +1,49 @@
define(function () {
return function (config) {
var self = this
var stats, timestamp
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 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) {
return d.statistics.clients ? d.statistics.clients : 0
}))
return d.statistics.clients ? d.statistics.clients : 0;
}));
var totalGateways = sum(d.nodes.all.filter(online).filter( function (d) {
return d.flags.gateway
}).map(one))
return d.flags.gateway;
}).map(one));
var nodetext = [{ count: totalOnlineNodes, label: "online" },
{ count: totalNewNodes, label: "neu" },
{ count: totalLostNodes, label: "verschwunden" }
].filter( function (d) { return d.count > 0 } )
.map( function (d) { return [d.count, d.label].join(" ") } )
.join(", ")
].filter( function (d) { return d.count > 0; } )
.map( function (d) { return [d.count, d.label].join(" "); } )
.join(", ");
stats.textContent = totalNodes + " Knoten " +
"(" + nodetext + "), " +
totalClients + " Client" + ( totalClients === 1 ? ", " : "s, " ) +
totalGateways + " Gateways"
totalGateways + " Gateways";
timestamp.textContent = "Diese Daten sind von " + d.timestamp.format("LLLL") + "."
}
timestamp.textContent = "Diese Daten sind von " + d.timestamp.format("LLLL") + ".";
};
self.render = function (el) {
var h2 = document.createElement("h2")
h2.textContent = config.siteName
el.appendChild(h2)
var h2 = document.createElement("h2");
h2.textContent = config.siteName;
el.appendChild(h2);
var p = document.createElement("p")
el.appendChild(p)
stats = document.createTextNode("")
p.appendChild(stats)
p.appendChild(document.createElement("br"))
timestamp = document.createTextNode("")
p.appendChild(timestamp)
}
var p = document.createElement("p");
el.appendChild(p);
stats = document.createTextNode("");
p.appendChild(stats);
p.appendChild(document.createElement("br"));
timestamp = document.createTextNode("");
p.appendChild(timestamp);
};
return self
}
})
return self;
};
});

View File

@ -1,93 +1,93 @@
define(["sorttable", "virtual-dom", "numeral"], function (SortTable, V, numeral) {
function getUptime(now, d) {
if (d.flags.online && "uptime" in d.statistics)
return Math.round(d.statistics.uptime)
return Math.round(d.statistics.uptime);
else if (!d.flags.online && "lastseen" in d)
return Math.round(-(now.unix() - d.lastseen.unix()))
return Math.round(-(now.unix() - d.lastseen.unix()));
}
function showUptime(uptime) {
var s = ""
uptime /= 3600
var s = "";
uptime /= 3600;
if (uptime !== undefined)
if (Math.abs(uptime) >= 24)
s = Math.round(uptime / 24) + "d"
s = Math.round(uptime / 24) + "d";
else
s = Math.round(uptime) + "h"
s = Math.round(uptime) + "h";
return s
return s;
}
var headings = [{ name: "Knoten",
sort: function (a, b) {
return a.nodeinfo.hostname.localeCompare(b.nodeinfo.hostname)
return a.nodeinfo.hostname.localeCompare(b.nodeinfo.hostname);
},
reverse: false
},
{ name: "Uptime",
sort: function (a, b) {
return a.uptime - b.uptime
return a.uptime - b.uptime;
},
reverse: true
},
{ name: "#Links",
sort: function (a, b) {
return a.meshlinks - b.meshlinks
return a.meshlinks - b.meshlinks;
},
reverse: true
},
{ name: "Clients",
sort: function (a, b) {
return ("clients" in a.statistics ? a.statistics.clients : -1) -
("clients" in b.statistics ? b.statistics.clients : -1)
("clients" in b.statistics ? b.statistics.clients : -1);
},
reverse: true
}]
}];
return function(router) {
function renderRow(d) {
var td1Content = []
var aClass = ["hostname", d.flags.online ? "online" : "offline"]
var td1Content = [];
var aClass = ["hostname", d.flags.online ? "online" : "offline"];
td1Content.push(V.h("a", { className: aClass.join(" "),
onclick: router.node(d),
href: "#"
}, d.nodeinfo.hostname))
}, d.nodeinfo.hostname));
if (has_location(d))
td1Content.push(V.h("span", {className: "icon ion-location"}))
td1Content.push(V.h("span", {className: "icon ion-location"}));
var td1 = V.h("td", td1Content)
var td2 = V.h("td", showUptime(d.uptime))
var td3 = V.h("td", d.meshlinks.toString())
var td4 = V.h("td", numeral("clients" in d.statistics ? d.statistics.clients : "").format("0,0"))
var td1 = V.h("td", td1Content);
var td2 = V.h("td", showUptime(d.uptime));
var td3 = V.h("td", d.meshlinks.toString());
var td4 = V.h("td", numeral("clients" in d.statistics ? d.statistics.clients : "").format("0,0"));
return V.h("tr", [td1, td2, td3, td4])
return V.h("tr", [td1, td2, td3, td4]);
}
var table = new SortTable(headings, 0, renderRow)
var table = new SortTable(headings, 0, renderRow);
this.render = function (d) {
var el = document.createElement("div")
d.appendChild(el)
var el = document.createElement("div");
d.appendChild(el);
var h2 = document.createElement("h2")
h2.textContent = "Alle Knoten"
el.appendChild(h2)
var h2 = document.createElement("h2");
h2.textContent = "Alle Knoten";
el.appendChild(h2);
el.appendChild(table.el)
}
el.appendChild(table.el);
};
this.setData = function (d) {
var data = d.nodes.all.map(function (e) {
var n = Object.create(e)
n.uptime = getUptime(d.now, e) || 0
n.meshlinks = e.meshlinks || 0
return n
})
var n = Object.create(e);
n.uptime = getUptime(d.now, e) || 0;
n.meshlinks = e.meshlinks || 0;
return n;
});
table.setData(data)
}
}
})
table.setData(data);
};
};
});

View File

@ -2,223 +2,223 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
function (Chroma, V, numeral, Filter, vercomp) {
return function (config, filterManager) {
var self = this
var scale = Chroma.scale("YlGnBu").mode("lab")
var self = this;
var scale = Chroma.scale("YlGnBu").mode("lab");
var statusTable = document.createElement("table")
statusTable.classList.add("proportion")
var statusTable = document.createElement("table");
statusTable.classList.add("proportion");
var fwTable = document.createElement("table")
fwTable.classList.add("proportion")
var fwTable = document.createElement("table");
fwTable.classList.add("proportion");
var hwTable = document.createElement("table")
hwTable.classList.add("proportion")
var hwTable = document.createElement("table");
hwTable.classList.add("proportion");
var geoTable = document.createElement("table")
geoTable.classList.add("proportion")
var geoTable = document.createElement("table");
geoTable.classList.add("proportion");
var autoTable = document.createElement("table")
autoTable.classList.add("proportion")
var autoTable = document.createElement("table");
autoTable.classList.add("proportion");
var uplinkTable = document.createElement("table")
uplinkTable.classList.add("proportion")
var uplinkTable = document.createElement("table");
uplinkTable.classList.add("proportion");
var gwNodesTable = document.createElement("table")
gwNodesTable.classList.add("proportion")
var gwNodesTable = document.createElement("table");
gwNodesTable.classList.add("proportion");
var gwClientsTable = document.createElement("table")
gwClientsTable.classList.add("proportion")
var gwClientsTable = document.createElement("table");
gwClientsTable.classList.add("proportion");
var siteTable = document.createElement("table")
siteTable.classList.add("proportion")
var siteTable = document.createElement("table");
siteTable.classList.add("proportion");
function showStatGlobal(o) {
return showStat(o)
return showStat(o);
}
function count(nodes, key, f) {
var dict = {}
var dict = {};
nodes.forEach( function (d) {
var v = dictGet(d, key.slice(0))
var v = dictGet(d, key.slice(0));
if (f !== undefined)
v = f(v)
v = f(v);
if (v === null)
return
return;
dict[v] = 1 + (v in dict ? dict[v] : 0)
})
dict[v] = 1 + (v in dict ? dict[v] : 0);
});
return Object.keys(dict).map(function (d) { return [d, dict[d], key, f] })
return Object.keys(dict).map(function (d) { return [d, dict[d], key, f]; });
}
function countClients(nodes, key, f) {
var dict = {}
var dict = {};
nodes.forEach( function (d) {
var v = dictGet(d, key.slice(0))
var v = dictGet(d, key.slice(0));
if (f !== undefined)
v = f(v)
v = f(v);
if (v === null)
return
return;
dict[v] = d.statistics.clients + (v in dict ? dict[v] : 0)
})
dict[v] = d.statistics.clients + (v in dict ? dict[v] : 0);
});
return Object.keys(dict).map(function (d) { return [d, dict[d], key, f] })
return Object.keys(dict).map(function (d) { return [d, dict[d], key, f]; });
}
function addFilter(filter) {
return function () {
filterManager.addFilter(filter)
filterManager.addFilter(filter);
return false
}
return false;
};
}
function fillTable(name, table, data) {
if (!table.last)
table.last = V.h("table")
table.last = V.h("table");
var max = 0
var max = 0;
data.forEach(function (d) {
if (d[1] > max)
max = d[1]
})
max = d[1];
});
var items = data.map(function (d) {
var v = d[1] / max
var c1 = Chroma.contrast(scale(v), "white")
var c2 = Chroma.contrast(scale(v), "black")
var v = d[1] / max;
var c1 = Chroma.contrast(scale(v), "white");
var c2 = Chroma.contrast(scale(v), "black");
var filter = new Filter(name, d[2], d[0], d[3])
var filter = new Filter(name, d[2], d[0], d[3]);
var a = V.h("a", { href: "#", onclick: addFilter(filter) }, d[0])
var a = V.h("a", { href: "#", onclick: addFilter(filter) }, d[0]);
var th = V.h("th", a)
var th = V.h("th", a);
var td = V.h("td", V.h("span", {style: {
width: Math.round(v * 100) + "%",
backgroundColor: scale(v).hex(),
color: c1 > c2 ? "white" : "black"
}}, numeral(d[1]).format("0,0")))
}}, numeral(d[1]).format("0,0")));
return V.h("tr", [th, td])
})
return V.h("tr", [th, td]);
});
var tableNew = V.h("table", items)
table = V.patch(table, V.diff(table.last, tableNew))
table.last = tableNew
var tableNew = V.h("table", items);
table = V.patch(table, V.diff(table.last, tableNew));
table.last = tableNew;
}
self.setData = function (data) {
var onlineNodes = data.nodes.all.filter(online)
var nodes = onlineNodes.concat(data.nodes.lost)
var nodeDict = {}
var onlineNodes = data.nodes.all.filter(online);
var nodes = onlineNodes.concat(data.nodes.lost);
var nodeDict = {};
data.nodes.all.forEach(function (d) {
nodeDict[d.nodeinfo.node_id] = d
})
nodeDict[d.nodeinfo.node_id] = d;
});
var statusDict = count(nodes, ["flags", "online"], function (d) {
return d ? "online" : "offline"
})
var fwDict = count(nodes, ["nodeinfo", "software", "firmware", "release"])
var hwDict = count(nodes, ["nodeinfo", "hardware", "model"])
return d ? "online" : "offline";
});
var fwDict = count(nodes, ["nodeinfo", "software", "firmware", "release"]);
var hwDict = count(nodes, ["nodeinfo", "hardware", "model"]);
var geoDict = count(nodes, ["nodeinfo", "location"], function (d) {
return d && d.longitude && d.latitude ? "ja" : "nein"
})
return d && d.longitude && d.latitude ? "ja" : "nein";
});
var autoDict = count(nodes, ["nodeinfo", "software", "autoupdater"], function (d) {
if (d === null)
return null
return null;
else if (d.enabled)
return d.branch
return d.branch;
else
return "(deaktiviert)"
})
return "(deaktiviert)";
});
var uplinkDict = count(nodes, ["flags", "uplink"], function (d) {
return d ? "ja" : "nein"
})
return d ? "ja" : "nein";
});
var gwNodesDict = count(onlineNodes, ["statistics", "gateway"], function (d) {
if (d === null)
return null
return null;
if (d in nodeDict)
return nodeDict[d].nodeinfo.hostname
return nodeDict[d].nodeinfo.hostname;
return d
})
return d;
});
var gwClientsDict = countClients(onlineNodes, ["statistics", "gateway"], function (d) {
if (d === null)
return null
return null;
if (d in nodeDict)
return nodeDict[d].nodeinfo.hostname
return nodeDict[d].nodeinfo.hostname;
return d
})
return d;
});
var siteDict = count(nodes, ["nodeinfo", "system", "site_code"], function (d) {
var rt = d
var rt = d;
if (config.siteNames)
config.siteNames.forEach( function (t) {
if(d === t.site)
rt = t.name
})
return rt
})
rt = t.name;
});
return rt;
});
fillTable("Status", statusTable, statusDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Firmware", fwTable, fwDict.sort(function (a, b) { return vercomp(b[0], a[0]) }))
fillTable("Hardware", hwTable, hwDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Koordinaten", geoTable, geoDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Uplink", uplinkTable, uplinkDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Autom. Updates", autoTable, autoDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Nodes an Gateway", gwNodesTable, gwNodesDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Clients an Gateway", gwClientsTable, gwClientsDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Site", siteTable, siteDict.sort(function (a, b) { return b[1] - a[1] }))
}
fillTable("Status", statusTable, statusDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Firmware", fwTable, fwDict.sort(function (a, b) { return vercomp(b[0], a[0]); }));
fillTable("Hardware", hwTable, hwDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Koordinaten", geoTable, geoDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Uplink", uplinkTable, uplinkDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Autom. Updates", autoTable, autoDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Nodes an Gateway", gwNodesTable, gwNodesDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Clients an Gateway", gwClientsTable, gwClientsDict.sort(function (a, b) { return b[1] - a[1]; }));
fillTable("Site", siteTable, siteDict.sort(function (a, b) { return b[1] - a[1]; }));
};
self.render = function (el) {
var h2
self.renderSingle(el, "Status", statusTable)
self.renderSingle(el, "Nodes an Gateway", gwNodesTable)
self.renderSingle(el, "Clients an Gateway", gwClientsTable)
self.renderSingle(el, "Firmwareversionen", fwTable)
self.renderSingle(el, "Uplink", uplinkTable)
self.renderSingle(el, "Hardwaremodelle", hwTable)
self.renderSingle(el, "Auf der Karte sichtbar", geoTable)
self.renderSingle(el, "Autoupdater", autoTable)
self.renderSingle(el, "Site", siteTable)
var h2;
self.renderSingle(el, "Status", statusTable);
self.renderSingle(el, "Nodes an Gateway", gwNodesTable);
self.renderSingle(el, "Clients an Gateway", gwClientsTable);
self.renderSingle(el, "Firmwareversionen", fwTable);
self.renderSingle(el, "Uplink", uplinkTable);
self.renderSingle(el, "Hardwaremodelle", hwTable);
self.renderSingle(el, "Auf der Karte sichtbar", geoTable);
self.renderSingle(el, "Autoupdater", autoTable);
self.renderSingle(el, "Site", siteTable);
if (config.globalInfos)
config.globalInfos.forEach(function (globalInfo) {
h2 = document.createElement("h2")
h2.textContent = globalInfo.name
el.appendChild(h2)
el.appendChild(showStatGlobal(globalInfo))
})
}
h2 = document.createElement("h2");
h2.textContent = globalInfo.name;
el.appendChild(h2);
el.appendChild(showStatGlobal(globalInfo));
});
};
self.renderSingle = function (el, heading, table) {
var h2
h2 = document.createElement("h2")
h2.textContent = heading
var h2;
h2 = document.createElement("h2");
h2.textContent = heading;
h2.onclick = function () {
table.classList.toggle("hidden")
}
el.appendChild(h2)
el.appendChild(table)
}
return self
}
})
table.classList.toggle("hidden");
};
el.appendChild(h2);
el.appendChild(table);
};
return self;
};
});

View File

@ -1,214 +1,214 @@
define(function () {
return function () {
var self = this
var objects = { nodes: {}, links: {} }
var targets = []
var views = {}
var currentView
var currentObject
var running = false
var self = this;
var objects = { nodes: {}, links: {} };
var targets = [];
var views = {};
var currentView;
var currentObject;
var running = false;
function saveState() {
var e = []
var e = [];
if (currentView)
e.push("v:" + currentView)
e.push("v:" + currentView);
if (currentObject) {
if ("node" in currentObject)
e.push("n:" + encodeURIComponent(currentObject.node.nodeinfo.node_id))
e.push("n:" + encodeURIComponent(currentObject.node.nodeinfo.node_id));
if ("link" in currentObject)
e.push("l:" + encodeURIComponent(currentObject.link.id))
e.push("l:" + encodeURIComponent(currentObject.link.id));
}
var s = "#!" + e.join(";")
var s = "#!" + e.join(";");
window.history.pushState(s, undefined, s)
window.history.pushState(s, undefined, s);
}
function resetView(push) {
push = trueDefault(push)
push = trueDefault(push);
targets.forEach( function (t) {
t.resetView()
})
t.resetView();
});
if (push) {
currentObject = undefined
saveState()
currentObject = undefined;
saveState();
}
}
function gotoNode(d) {
if (!d)
return false
return false;
targets.forEach( function (t) {
t.gotoNode(d)
})
t.gotoNode(d);
});
return true
return true;
}
function gotoLink(d) {
if (!d)
return false
return false;
targets.forEach( function (t) {
t.gotoLink(d)
})
t.gotoLink(d);
});
return true
return true;
}
function gotoLocation(d) {
if (!d)
return false
return false;
targets.forEach( function (t) {
if(!t.gotoLocation)console.warn("has no gotoLocation", t)
t.gotoLocation(d)
})
if(!t.gotoLocation)console.warn("has no gotoLocation", t);
t.gotoLocation(d);
});
return true
return true;
}
function loadState(s) {
if (!s)
return false
return false;
s = decodeURIComponent(s)
s = decodeURIComponent(s);
if (!s.startsWith("#!"))
return false
return false;
var targetSet = false
var targetSet = false;
s.slice(2).split(";").forEach(function (d) {
var args = d.split(":")
var args = d.split(":");
if (args[0] === "v" && args[1] in views) {
currentView = args[1]
views[args[1]]()
currentView = args[1];
views[args[1]]();
}
var id
var id;
if (args[0] === "n") {
id = args[1]
id = args[1];
if (id in objects.nodes) {
currentObject = { node: objects.nodes[id] }
gotoNode(objects.nodes[id])
targetSet = true
currentObject = { node: objects.nodes[id] };
gotoNode(objects.nodes[id]);
targetSet = true;
}
}
if (args[0] === "l") {
id = args[1]
id = args[1];
if (id in objects.links) {
currentObject = { link: objects.links[id] }
gotoLink(objects.links[id])
targetSet = true
currentObject = { link: objects.links[id] };
gotoLink(objects.links[id]);
targetSet = true;
}
}
})
});
return targetSet
return targetSet;
}
self.start = function () {
running = true
running = true;
if (!loadState(window.location.hash))
resetView(false)
resetView(false);
window.onpopstate = function (d) {
if (!loadState(d.state))
resetView(false)
}
}
resetView(false);
};
};
self.view = function (d) {
if (d in views) {
views[d]()
views[d]();
if (!currentView || running)
currentView = d
currentView = d;
if (!running)
return
return;
saveState()
saveState();
if (!currentObject) {
resetView(false)
return
resetView(false);
return;
}
if ("node" in currentObject)
gotoNode(currentObject.node)
gotoNode(currentObject.node);
if ("link" in currentObject)
gotoLink(currentObject.link)
gotoLink(currentObject.link);
}
}
};
self.node = function (d) {
return function () {
if (gotoNode(d)) {
currentObject = { node: d }
saveState()
currentObject = { node: d };
saveState();
}
return false
}
}
return false;
};
};
self.link = function (d) {
return function () {
if (gotoLink(d)) {
currentObject = { link: d }
saveState()
currentObject = { link: d };
saveState();
}
return false
}
}
return false;
};
};
self.gotoLocation = gotoLocation
self.gotoLocation = gotoLocation;
self.reset = function () {
resetView()
}
resetView();
};
self.addTarget = function (d) {
targets.push(d)
}
targets.push(d);
};
self.removeTarget = function (d) {
targets = targets.filter( function (e) {
return d !== e
})
}
return d !== e;
});
};
self.addView = function (k, d) {
views[k] = d
}
views[k] = d;
};
self.setData = function (data) {
objects.nodes = {}
objects.links = {}
objects.nodes = {};
objects.links = {};
data.nodes.all.forEach( function (d) {
objects.nodes[d.nodeinfo.node_id] = d
})
objects.nodes[d.nodeinfo.node_id] = d;
});
data.graph.links.forEach( function (d) {
objects.links[d.id] = d
})
}
objects.links[d.id] = d;
});
};
return self
}
})
return self;
};
});

View File

@ -1,49 +1,49 @@
define([], function () {
return function (el) {
var self = this
var self = this;
var sidebar = document.createElement("div")
sidebar.classList.add("sidebar")
el.appendChild(sidebar)
var sidebar = document.createElement("div");
sidebar.classList.add("sidebar");
el.appendChild(sidebar);
var button = document.createElement("button")
sidebar.appendChild(button)
var button = document.createElement("button");
sidebar.appendChild(button);
button.classList.add("sidebarhandle")
button.classList.add("sidebarhandle");
button.onclick = function () {
sidebar.classList.toggle("hidden")
}
sidebar.classList.toggle("hidden");
};
var container = document.createElement("div")
container.classList.add("container")
sidebar.appendChild(container)
var container = document.createElement("div");
container.classList.add("container");
sidebar.appendChild(container);
self.getWidth = function () {
if (sidebar.classList.contains("hidden"))
return 0
return 0;
var small = window.matchMedia("(max-width: 630pt)")
return small.matches ? 0 : sidebar.offsetWidth
}
var small = window.matchMedia("(max-width: 630pt)");
return small.matches ? 0 : sidebar.offsetWidth;
};
self.add = function (d) {
d.render(container)
}
d.render(container);
};
self.ensureVisible = function () {
sidebar.classList.remove("hidden")
}
sidebar.classList.remove("hidden");
};
self.hide = function () {
container.classList.add("hidden")
}
container.classList.add("hidden");
};
self.reveal = function () {
container.classList.remove("hidden")
}
container.classList.remove("hidden");
};
self.container = sidebar
self.container = sidebar;
return self
}
})
return self;
};
});

View File

@ -1,63 +1,63 @@
define(["moment", "virtual-dom"], function (moment, V) {
return function(nodes, field, router, title) {
var self = this
var el, tbody
var self = this;
var el, tbody;
self.render = function (d) {
el = document.createElement("div")
d.appendChild(el)
}
el = document.createElement("div");
d.appendChild(el);
};
self.setData = function (data) {
var list = data.nodes[nodes]
var list = data.nodes[nodes];
if (list.length === 0) {
while (el.firstChild)
el.removeChild(el.firstChild)
el.removeChild(el.firstChild);
tbody = null
tbody = null;
return
return;
}
if (!tbody) {
var h2 = document.createElement("h2")
h2.textContent = title
el.appendChild(h2)
var h2 = document.createElement("h2");
h2.textContent = title;
el.appendChild(h2);
var table = document.createElement("table")
el.appendChild(table)
var table = document.createElement("table");
el.appendChild(table);
tbody = document.createElement("tbody")
tbody.last = V.h("tbody")
table.appendChild(tbody)
tbody = document.createElement("tbody");
tbody.last = V.h("tbody");
table.appendChild(tbody);
}
var items = list.map( function (d) {
var time = moment(d[field]).from(data.now)
var td1Content = []
var time = moment(d[field]).from(data.now);
var td1Content = [];
var aClass = ["hostname", d.flags.online ? "online" : "offline"]
var aClass = ["hostname", d.flags.online ? "online" : "offline"];
td1Content.push(V.h("a", { className: aClass.join(" "),
onclick: router.node(d),
href: "#"
}, d.nodeinfo.hostname))
}, d.nodeinfo.hostname));
if (has_location(d))
td1Content.push(V.h("span", {className: "icon ion-location"}))
td1Content.push(V.h("span", {className: "icon ion-location"}));
var td1 = V.h("td", td1Content)
var td2 = V.h("td", time)
var td1 = V.h("td", td1Content);
var td2 = V.h("td", time);
return V.h("tr", [td1, td2])
})
return V.h("tr", [td1, td2]);
});
var tbodyNew = V.h("tbody", items)
tbody = V.patch(tbody, V.diff(tbody.last, tbodyNew))
tbody.last = tbodyNew
}
var tbodyNew = V.h("tbody", items);
tbody = V.patch(tbody, V.diff(tbody.last, tbodyNew));
tbody.last = tbodyNew;
};
return self
}
})
return self;
};
});

View File

@ -1,57 +1,57 @@
define(["virtual-dom"], function (V) {
return function(headings, sortIndex, renderRow) {
var data
var sortReverse = false
var el = document.createElement("table")
var elLast = V.h("table")
var data;
var sortReverse = false;
var el = document.createElement("table");
var elLast = V.h("table");
function sortTable(i) {
sortReverse = i === sortIndex ? !sortReverse : false
sortIndex = i
sortReverse = i === sortIndex ? !sortReverse : false;
sortIndex = i;
updateView()
updateView();
}
function sortTableHandler(i) {
return function () { sortTable(i) }
return function () { sortTable(i); };
}
function updateView() {
var children = []
var children = [];
if (data.length !== 0) {
var th = headings.map(function (d, i) {
var properties = { onclick: sortTableHandler(i),
className: "sort-header"
}
};
if (sortIndex === i)
properties.className += sortReverse ? " sort-up" : " sort-down"
properties.className += sortReverse ? " sort-up" : " sort-down";
return V.h("th", properties, d.name)
})
return V.h("th", properties, d.name);
});
var links = data.slice(0).sort(headings[sortIndex].sort)
var links = data.slice(0).sort(headings[sortIndex].sort);
if (headings[sortIndex].reverse ? !sortReverse : sortReverse)
links = links.reverse()
links = links.reverse();
children.push(V.h("thead", V.h("tr", th)))
children.push(V.h("tbody", links.map(renderRow)))
children.push(V.h("thead", V.h("tr", th)));
children.push(V.h("tbody", links.map(renderRow)));
}
var elNew = V.h("table", children)
el = V.patch(el, V.diff(elLast, elNew))
elLast = elNew
var elNew = V.h("table", children);
el = V.patch(el, V.diff(elLast, elNew));
elLast = elNew;
}
this.setData = function (d) {
data = d
updateView()
}
data = d;
updateView();
};
this.el = el
this.el = el;
return this
}
})
return this;
};
});

View File

@ -1,57 +1,57 @@
define([], function () {
return function () {
var self = this
var self = this;
var tabs = document.createElement("ul")
tabs.classList.add("tabs")
var tabs = document.createElement("ul");
tabs.classList.add("tabs");
var container = document.createElement("div")
var container = document.createElement("div");
function gotoTab(li) {
for (var i = 0; i < tabs.children.length; i++)
tabs.children[i].classList.remove("visible")
tabs.children[i].classList.remove("visible");
while (container.firstChild)
container.removeChild(container.firstChild)
container.removeChild(container.firstChild);
li.classList.add("visible")
li.classList.add("visible");
var tab = document.createElement("div")
tab.classList.add("tab")
container.appendChild(tab)
li.child.render(tab)
var tab = document.createElement("div");
tab.classList.add("tab");
container.appendChild(tab);
li.child.render(tab);
}
function switchTab() {
gotoTab(this)
gotoTab(this);
return false
return false;
}
self.add = function (title, d) {
var li = document.createElement("li")
li.textContent = title
li.onclick = switchTab
li.child = d
tabs.appendChild(li)
var li = document.createElement("li");
li.textContent = title;
li.onclick = switchTab;
li.child = d;
tabs.appendChild(li);
var anyVisible = false
var anyVisible = false;
for (var i = 0; i < tabs.children.length; i++)
if (tabs.children[i].classList.contains("visible")) {
anyVisible = true
break
anyVisible = true;
break;
}
if (!anyVisible)
gotoTab(li)
}
gotoTab(li);
};
self.render = function (el) {
el.appendChild(tabs)
el.appendChild(container)
}
el.appendChild(tabs);
el.appendChild(container);
};
return self
}
})
return self;
};
});

View File

@ -1,35 +1,35 @@
define(function () {
return function (config) {
function setTitle(d) {
var title = [config.siteName]
var title = [config.siteName];
if (d !== undefined)
title.push(d)
title.push(d);
document.title = title.join(": ")
document.title = title.join(": ");
}
this.resetView = function () {
setTitle()
}
setTitle();
};
this.gotoNode = function (d) {
if (d)
setTitle(d.nodeinfo.hostname)
}
setTitle(d.nodeinfo.hostname);
};
this.gotoLink = function (d) {
if (d)
setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " " + d.target.node.nodeinfo.hostname)
}
setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + " " + d.target.node.nodeinfo.hostname);
};
this.gotoLocation = function() {
//ignore
}
};
this.destroy = function () {
}
};
return this
}
})
return this;
};
});

View File

@ -1,60 +1,60 @@
define([], function () {
function order(c) {
if (/^\d$/.test(c))
return 0
return 0;
else if (/^[a-z]$/i.test(c))
return c.charCodeAt(0)
return c.charCodeAt(0);
else if (c === "~")
return -1
return -1;
else if (c)
return c.charCodeAt(0) + 256
return c.charCodeAt(0) + 256;
else
return 0
return 0;
}
// Based on dpkg code
function vercomp(a, b) {
var apos = 0, bpos = 0
var apos = 0, bpos = 0;
while (apos < a.length || bpos < b.length) {
var firstDiff = 0
var firstDiff = 0;
while ((apos < a.length && !/^\d$/.test(a[apos])) || (bpos < b.length && !/^\d$/.test(b[bpos]))) {
var ac = order(a[apos])
var bc = order(b[bpos])
var ac = order(a[apos]);
var bc = order(b[bpos]);
if (ac !== bc)
return ac - bc
return ac - bc;
apos++
bpos++
apos++;
bpos++;
}
while (a[apos] === "0")
apos++
apos++;
while (b[bpos] === "0")
bpos++
bpos++;
while (/^\d$/.test(a[apos]) && /^\d$/.test(b[bpos])) {
if (firstDiff === 0)
firstDiff = a.charCodeAt(apos) - b.charCodeAt(bpos)
firstDiff = a.charCodeAt(apos) - b.charCodeAt(bpos);
apos++
bpos++
apos++;
bpos++;
}
if (/^\d$/.test(a[apos]))
return 1
return 1;
if (/^\d$/.test(b[bpos]))
return -1
return -1;
if (firstDiff !== 0)
return firstDiff
return firstDiff;
}
return 0
return 0;
}
return vercomp
})
return vercomp;
});

View File

@ -5,7 +5,7 @@ module.exports = function(grunt) {
html: {
options: {
process: function (content) {
return content.replace("#revision#", grunt.option("gitRevision"))
return content.replace("#revision#", grunt.option("gitRevision"));
}
},
src: ["*.html"],
@ -115,11 +115,11 @@ module.exports = function(grunt) {
}
}
}
})
});
grunt.loadNpmTasks("grunt-bower-install-simple")
grunt.loadNpmTasks("grunt-contrib-copy")
grunt.loadNpmTasks("grunt-contrib-requirejs")
grunt.loadNpmTasks("grunt-sass")
grunt.loadNpmTasks("grunt-postcss")
}
grunt.loadNpmTasks("grunt-bower-install-simple");
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-contrib-requirejs");
grunt.loadNpmTasks("grunt-sass");
grunt.loadNpmTasks("grunt-postcss");
};

View File

@ -3,7 +3,7 @@ module.exports = function (grunt) {
clean: {
build: ["build/**/*", "node_modules/grunt-newer/.cache"]
}
})
});
grunt.loadNpmTasks("grunt-contrib-clean")
}
grunt.loadNpmTasks("grunt-contrib-clean");
};

View File

@ -24,8 +24,8 @@ module.exports = function (grunt) {
tasks: []
}
}
})
});
grunt.loadNpmTasks("grunt-contrib-connect")
grunt.loadNpmTasks("grunt-contrib-watch")
}
grunt.loadNpmTasks("grunt-contrib-connect");
grunt.loadNpmTasks("grunt-contrib-watch");
};

View File

@ -14,7 +14,6 @@ module.exports = function (grunt) {
eslint: {
options: {
rules: {
"semi": [2, "never"],
"curly": [2, "multi"],
"strict": [2, "never"],
"no-multi-spaces": 0,
@ -31,8 +30,8 @@ module.exports = function (grunt) {
src: ["Gruntfile.js", "tasks/*.js"]
}
}
})
});
grunt.loadNpmTasks("grunt-check-dependencies")
grunt.loadNpmTasks("grunt-eslint")
}
grunt.loadNpmTasks("grunt-check-dependencies");
grunt.loadNpmTasks("grunt-eslint");
};