diff --git a/webroot/.eslintrc b/webroot/.eslintrc
new file mode 100644
index 0000000..c923bba
--- /dev/null
+++ b/webroot/.eslintrc
@@ -0,0 +1,35 @@
+{
+ extends: eslint:all,
+ rules: {
+ no-tabs: [off],
+ indent: [error, tab],
+ quotes: [error, single],
+ padded-blocks: [error, { blocks: never }],
+ no-console: [error, { allow: [log, warn, error] }],
+ func-style: [error, declaration],
+ object-curly-newline: off,
+ wrap-iife: [error, inside],
+ object-shorthand: ["error", "always", { "avoidQuotes": true }],
+ require-jsdoc: [off],
+ max-statements: [off],
+ no-magic-numbers: ["error", { "ignore": [0,1,-1] }],
+ sort-vars: [off],
+ max-len: [off],
+ id-length: [error, { exceptions: ["i"] }],
+ no-ternary: [off]
+
+ },
+ env: {
+ es6: true
+ },
+ globals: {
+ L: true,
+ moment: true,
+ Navigo: true,
+ document: true,
+ window: true,
+ location: true,
+ navigator: true,
+ console: true,
+ }
+}
diff --git a/webroot/css/main.css b/webroot/css/main.css
index 83de703..c945704 100644
--- a/webroot/css/main.css
+++ b/webroot/css/main.css
@@ -1,180 +1,180 @@
body {
- position: relative;
- margin: 0px;
- font-size: 15px;
- color: #333;
- line-height: 1.3;
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+ position: relative;
+ margin: 0px;
+ font-size: 15px;
+ color: #333;
+ line-height: 1.3;
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
.status {
- float: right;
- background: #009ee0;
- width: 50px;
- height: 50px;
+ float: right;
+ background: #009ee0;
+ width: 50px;
+ height: 50px;
}
.status.connecting {
- background: #ffb400;
+ background: #ffb400;
}
.status.offline {
- background: #dc0067;
+ background: #dc0067;
}
span.online {
- color: #009ee0;
+ color: #009ee0;
}
span.offline {
- color: #dc0067;
+ color: #dc0067;
}
h1 {
- border-bottom: 4px solid #dc0067;
+ border-bottom: 4px solid #dc0067;
}
header {
- background-color: #373636;
- max-width: 100%;
- height: 50px;
+ background-color: #373636;
+ max-width: 100%;
+ height: 50px;
}
header > div {
- display: inline-block;
+ display: inline-block;
}
nav {
- display: inline-block;
- font-weight: 700;
- width: 100%;
+ display: inline-block;
+ font-weight: 700;
+ width: 100%;
}
nav ul {
- padding: 0;
- margin: 0;
- list-style-type: none;
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
}
nav li {
- float:left;
- display: inline-block;
+ float:left;
+ display: inline-block;
}
nav li:hover, nav.active {
- background: rgba(255, 255, 255, 0.2);
+ background: rgba(255, 255, 255, 0.2);
}
nav li a, nav li span {
- display: inline-block;
- cursor: pointer;
- text-decoration: none !important;
- text-align: center;
- text-transform: uppercase;
- color: inherit;
- box-sizing: border-box;
- padding: 1.1em .5em;
- height: 50px;
+ display: inline-block;
+ cursor: pointer;
+ text-decoration: none !important;
+ text-align: center;
+ text-transform: uppercase;
+ color: inherit;
+ box-sizing: border-box;
+ padding: 1.1em .5em;
+ height: 50px;
}
nav > ul > .item-1 {
- background: #ffb400;
- color: #000;
+ background: #ffb400;
+ color: #000;
}
nav > ul > .item-2 {
- background: #dc0067;
- color: #fff;
+ background: #dc0067;
+ color: #fff;
}
nav > ul > .item-3 {
- background: #ccc;
- color: #000;
+ background: #ccc;
+ color: #000;
}
.notifications {
- position: absolute;
- right: 1em;
+ position: absolute;
+ right: 1em;
}
.notify {
- position: relative;
- min-height: 1em;
- margin: 1em 0;
- padding: 1em 1.5em;
- color: rgba(0,0,0,.87);
- -webkit-transition: opacity .1s ease,color .1s ease,background .1s ease,box-shadow .1s ease;
- transition: opacity .1s ease,color .1s ease,background .1s ease,box-shadow .1s ease;
- box-shadow: 0 0 0 1px rgba(34,36,38,.22) inset, 0 0 0 0 transparent;
- background: #ccc;
- color: #000;
+ position: relative;
+ min-height: 1em;
+ margin: 1em 0;
+ padding: 1em 1.5em;
+ color: rgba(0,0,0,.87);
+ -webkit-transition: opacity .1s ease,color .1s ease,background .1s ease,box-shadow .1s ease;
+ transition: opacity .1s ease,color .1s ease,background .1s ease,box-shadow .1s ease;
+ box-shadow: 0 0 0 1px rgba(34,36,38,.22) inset, 0 0 0 0 transparent;
+ background: #ccc;
+ color: #000;
}
.notify.success {
- background: #009ee0;
- color: #fff;
+ background: #009ee0;
+ color: #fff;
}
.notify.warn {
- background: #ffb400;
- color: #000;
+ background: #ffb400;
+ color: #000;
}
.notify.error {
- background: #dc0067;
- color: #fff;
+ background: #dc0067;
+ color: #fff;
}
thead {
- font-size: 1.3em;
- font-weight: bold;
- cursor: default;
+ font-size: 1.3em;
+ font-weight: bold;
+ cursor: default;
}
thead tr th{
- border-bottom: 4px solid #dc0067;
+ border-bottom: 4px solid #dc0067;
}
table th > input {
- border: none;
- color: #000;
- font-weight: bold;
- background: #fff;
+ border: none;
+ color: #000;
+ font-weight: bold;
+ background: #fff;
}
table th.sortable.sort-down:after {
- content: " \25BC"
+ content: " \25BC"
}
table th.sortable.sort-up:after {
- content: " \25B2"
+ content: " \25B2"
}
table th.sortable:not(.sort-down):not(.sort-up):after {
- content: " \25B4\25BE";
+ content: " \25B4\25BE";
}
table.nodes, table.stats {
- width: 100%;
+ width: 100%;
}
table.nodes td > span{
- display: block;
+ display: block;
}
table.nodes tbody tr:nth-child(even) {
- background: #eee;
+ background: #eee;
}
table.nodes tbody tr:nth-child(odd) {
- background: #fff;
+ background: #fff;
}
table.nodes tbody tr:hover {
- background: #ccc;
+ background: #ccc;
}
table.nodes tbody tr.offline{
- background: #ffb400;
+ background: #ffb400;
}
table.nodes tbody tr.offline:hover{
- background: #dc0067;
+ background: #dc0067;
}
table tr.line td,table tr.line th {
- border-bottom: 1px solid #ffb400;
+ border-bottom: 1px solid #ffb400;
}
table.stats td {
- text-align: center;
+ text-align: center;
}
.btn {
- display: inline-block;
- padding: .3em .5em;
- border-radius: 1em;
- color: #fff;
- background-color: #dc0067;
- text-align: center;
- cursor: pointer;
+ display: inline-block;
+ padding: .3em .5em;
+ border-radius: 1em;
+ color: #fff;
+ background-color: #dc0067;
+ text-align: center;
+ cursor: pointer;
}
.btn:hover {
- background: lighten(#dc0067, 5%);
+ background: lighten(#dc0067, 5%);
}
a.btn:hover {
- text-decoration: none;
+ text-decoration: none;
}
a {
- color: #dc0067;
- text-decoration: none;
+ color: #dc0067;
+ text-decoration: none;
}
diff --git a/webroot/css/map.css b/webroot/css/map.css
index ea20aee..2d4c447 100644
--- a/webroot/css/map.css
+++ b/webroot/css/map.css
@@ -1,42 +1,42 @@
.leaflet-container .node {
- width: 3px;
- height: 3px;
- background-color: rgba(0,0,255,0.5);
- border: 2px solid white;
- border-radius: 10px;
+ width: 3px;
+ height: 3px;
+ background-color: rgba(0,0,255,0.5);
+ border: 2px solid white;
+ border-radius: 10px;
}
.leaflet-container .node.offline {
- background-color: rgba(255,0,0,0.5);
+ background-color: rgba(255,0,0,0.5);
}
.leaflet-container .node.client24 {
- border-left: 3px solid green;
+ border-left: 3px solid green;
}
.leaflet-container .node.client5 {
- border-border: 3px solid green;
+ border-border: 3px solid green;
}
.leaflet-container .node.client24-warn {
- border-left: 3px solid yellow;
+ border-left: 3px solid yellow;
}
.leaflet-container .node.client5-warn {
- border-border: 3px solid yellow;
+ border-border: 3px solid yellow;
}
.leaflet-container .node.client24-crit {
- border-left: 3px solid red;
+ border-left: 3px solid red;
}
.leaflet-container .node.client5-crit {
- border-border: 3px solid red;
+ border-border: 3px solid red;
}
.leaflet-container .nodeicon-label {
- font-size: 12px;
- font-weight: lighter;
+ font-size: 12px;
+ font-weight: lighter;
}
.leaflet-container .nodeicon-label table {
- width: 100%;
+ width: 100%;
}
.leaflet-container .nodeicon-label td {
- border-top: 1px solid #999;
- text-align: right;
+ border-top: 1px solid #999;
+ text-align: right;
}
.leaflet-container .nodeicon-label td:first-child {
- text-align: left;
+ text-align: left;
}
diff --git a/webroot/index.html b/webroot/index.html
index d8d63c5..89fb38b 100644
--- a/webroot/index.html
+++ b/webroot/index.html
@@ -1,47 +1,46 @@
-
-
-
- FreifunkManager
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ FreifunkManager
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webroot/js/config.js b/webroot/js/config.js
index 94fbdaf..3727b91 100644
--- a/webroot/js/config.js
+++ b/webroot/js/config.js
@@ -1,60 +1,88 @@
/* exported config */
-var config = {
- title: 'FreifunkManager - Breminale',
- backend: 'ws://'+location.host+'/websocket',
- map: {
- view: {bound: [53.07093, 8.79464], zoom: 17},
- maxZoom: 20,
- tileLayer: 'https://tiles.bremen.freifunk.net/{z}/{x}/{y}.png',
- /* heatmap settings
+/* eslint no-magic-numbers: "off"*/
+/* eslint sort-keys: "off"*/
+
+const config = {
+ 'title': 'FreifunkManager - Breminale',
+ 'backend': `ws://${location.host}/websocket`,
+ 'map': {
+ 'view': {
+ 'bound': [53.07093, 8.79464],
+ 'zoom': 17
+ },
+ 'maxZoom': 20,
+ 'tileLayer': 'https://tiles.bremen.freifunk.net/{z}/{x}/{y}.png',
+
+ /* Heatmap settings
size: in meters (default: 30km)
opacity: in percent/100 (default: 1)
gradientTexture: url-to-texture-image (default: false)
alphaRange: change transparency in heatmap (default: 1)
autoresize: resize heatmap when map size changes (default: false)
*/
- heatmap: {
- wifi24: {size: 230, opacity: 0.5, alphaRange: 1},
- wifi5: {size: 230, opacity: 0.5, alphaRange: 1}
- },
- icon:{
- warn:{wifi24:20,wifi5:20},
- crit:{wifi24:30,wifi5:30}
- },
- geojson: {
- url: 'http://events.ffhb.de/data/ground.geojson',
- pointToLayer: function (feature, latlng){
- feature.properties.radius = 10;
- return L.circleMarker(latlng, feature.properties);
- },
- onEachFeature: function(feature, layer) {
- if(feature.properties.name.length >0){
- layer.bindTooltip(feature.properties.name);
- }
- },
- style: function(feature){
- if(feature.geometry.type === 'LineString' || feature.geometry.type === 'Polygon'){
- return {
- color: feature.properties.stroke,
- opacity:feature.properties['stroke-opacity'],
- fillColor: feature.properties.fill,
- fillOpacity:feature.properties['fill-opacity'],
- stroke: true,
- weight: feature.properties['stroke-width'],
- lineCap: 'round',
- lineJoin: 'round'
- };
- }
- return {
- color: feature.properties['marker-color'],
- fillColor: feature.properties['marker-color'],
- fillOpacity: 0.2,
- weight: 2,
- stroke: true
- };
- }
- }
- },
+ 'heatmap': {
+ 'wifi24': {
+ 'size': 230,
+ 'opacity': 0.5,
+ 'alphaRange': 1
+ },
+ 'wifi5': {
+ 'size': 230,
+ 'opacity': 0.5,
+ 'alphaRange': 1
+ }
+ },
+ 'icon': {
+ 'warn': {
+ 'wifi24': 20,
+ 'wifi5': 20
+ },
+ 'crit': {
+ 'wifi24': 30,
+ 'wifi5': 30
+ }
+ },
+ 'geojson': {
+ 'url': 'http://events.ffhb.de/data/ground.geojson',
+ 'pointToLayer': function pointToLayer (feature, latlng) {
+ 'use strict';
+ feature.properties.radius = 10;
+
+ return L.circleMarker(latlng, feature.properties);
+ },
+ 'onEachFeature': function onEachFeature (feature, layer) {
+ 'use strict';
+
+ if (feature.properties.name.length > 0) {
+ layer.bindTooltip(feature.properties.name);
+ }
+ },
+ 'style': function style (feature) {
+ 'use strict';
+
+ if (feature.geometry.type === 'LineString' || feature.geometry.type === 'Polygon') {
+ return {
+ 'color': feature.properties.stroke,
+ 'opacity': feature.properties['stroke-opacity'],
+ 'fillColor': feature.properties.fill,
+ 'fillOpacity': feature.properties['fill-opacity'],
+ 'stroke': true,
+ 'weight': feature.properties['stroke-width'],
+ 'lineCap': 'round',
+ 'lineJoin': 'round'
+ };
+ }
+
+ return {
+ 'color': feature.properties['marker-color'],
+ 'fillColor': feature.properties['marker-color'],
+ 'fillOpacity': 0.2,
+ 'weight': 2,
+ 'stroke': true
+ };
+ }
+ }
+ }
};
diff --git a/webroot/js/domlib.js b/webroot/js/domlib.js
index a3c1835..584754c 100644
--- a/webroot/js/domlib.js
+++ b/webroot/js/domlib.js
@@ -1,16 +1,22 @@
/* exported domlin */
-var domlib = {};
-(function(){
- domlib.newAt = function(at,eltype) {
- var el = document.createElement(eltype);
- at.appendChild(el);
- return el;
- };
- domlib.removeChildren = function(el) {
- if(el)
- while(el.firstChild) {
- el.removeChild(el.firstChild);
- }
- };
+const domlib = {};
+
+(function init () {
+ 'use strict';
+
+ domlib.newAt = function newAt (at, eltype) {
+ const el = document.createElement(eltype);
+
+ at.appendChild(el);
+
+ return el;
+ };
+ domlib.removeChildren = function removeChildren (el) {
+ if (el) {
+ while (el.firstChild) {
+ el.removeChild(el.firstChild);
+ }
+ }
+ };
})();
diff --git a/webroot/js/gui.js b/webroot/js/gui.js
index 219389f..af1e74b 100644
--- a/webroot/js/gui.js
+++ b/webroot/js/gui.js
@@ -1,74 +1,100 @@
/* exported gui,router */
/* globals socket,notify,domlib,guiList,guiMap,guiStats,guiNode */
-var gui = {};
-var router = new Navigo(null, true, '#');
-(function(){
- var currentView = {bind:function(){},render:function(){}};
+const gui = {},
+ router = new Navigo(null, true, '#');
- function render() {
- var status = document.getElementsByClassName('status')[0];
- if (status === undefined){
- console.log("unable to render, render later");
- window.setTimeout(render,100);
- return;
- }
- status.classList.remove('connecting','offline');
- if(socket.readyState !== 1){
- status.classList.add(((socket.readyState===0 || socket.readyState===2)?'connecting':(socket.readyState===1)?'':'offline'));
- }
- notify.bind(document.getElementsByClassName('notifications')[0]);
+(function init () {
+ 'use strict';
- currentView.render();
- router.resolve();
- }
+ const GUI_RENDER_DEBOUNCER_TIME = 100;
- function setView(c){
- currentView = c;
- var main = document.querySelector('main');
- domlib.removeChildren(main);
- currentView.bind(main);
- currentView.render();
- }
+ let currentView = {
+ 'bind': function bind () {
+ console.warn('Do not run dummies');
+ },
+ // eslint-disable-next-line func-name-matching
+ 'render': function renderDummy () {
+ console.warn('DO not run dummies');
+ }
+ };
- router.on({
- '/list': function () {
- setView(guiList);
- },
- '/map':function(){
- setView(guiMap);
- },
- '/statistics':function(){
- setView(guiStats);
- },
- '/n/:nodeID': {
- as: 'node',
- uses: function (params) {
- guiNode.setNodeID(params['nodeID'].toLowerCase());
- setView(guiNode);
- }
- },
- });
- router.on(function () {
- router.navigate('/list');
- });
+ function renderView () {
+ // eslint-disable-next-line prefer-destructuring
+ const status = document.getElementsByClassName('status')[0];
- gui.render = function () {
- var timeout;
+ if (!status) {
+ console.log('unable to render, render later');
+ window.setTimeout(renderView, GUI_RENDER_DEBOUNCER_TIME);
- function reset () {
- timeout = null;
- }
+ return;
+ }
+ status.classList.remove('connecting', 'offline');
+ if (socket.readyState !== 1) {
+ let statusClass = 'offline';
- if (timeout){
- console("skip rendering, because to often");
- window.clearTimeout(timeout);
- } else {
- render();
- }
- timeout = window.setTimeout(reset, 100);
- };
+ // eslint-disable-next-line no-magic-numbers
+ if (socket.readyState === 0 || socket.readyState === 2) {
+ statusClass = 'connecting';
+ }
+ status.classList.add(statusClass);
+ }
- window.onload = gui.render;
+ // eslint-disable-next-line prefer-destructuring
+ notify.bind(document.getElementsByClassName('notifications')[0]);
+
+ currentView.render();
+ router.resolve();
+ }
+
+ function setView (toView) {
+ currentView = toView;
+ const main = document.querySelector('main');
+
+ domlib.removeChildren(main);
+ currentView.bind(main);
+ currentView.render();
+ }
+
+ router.on({
+ '/list': function routerList () {
+ setView(guiList);
+ },
+ '/map': function routerMap () {
+ setView(guiMap);
+ },
+ '/n/:nodeID': {
+ 'as': 'node',
+ // eslint-disable-next-line func-name-matching
+ 'uses': function routerNode (params) {
+ guiNode.setNodeID(params.nodeID.toLowerCase());
+ setView(guiNode);
+ }
+ },
+ '/statistics': function routerStats () {
+ setView(guiStats);
+ }
+ });
+ router.on(() => {
+ router.navigate('/list');
+ });
+
+ gui.render = function render () {
+ let timeout = false;
+
+ function reset () {
+ timeout = null;
+ }
+
+ if (timeout) {
+ console('skip rendering, because to often');
+ window.clearTimeout(timeout);
+ } else {
+ renderView();
+ }
+ timeout = window.setTimeout(reset, GUI_RENDER_DEBOUNCER_TIME);
+ };
+
+ window.onload = gui.render;
})();
diff --git a/webroot/js/gui_list.js b/webroot/js/gui_list.js
index 553e05a..e8ff989 100644
--- a/webroot/js/gui_list.js
+++ b/webroot/js/gui_list.js
@@ -1,239 +1,278 @@
/* exported guiList */
/* global domlib,store,router */
-var guiList = {};
+const guiList = {};
-(function(){
- var view = guiList;
- var container, el;
+(function init () {
+ 'use strict';
- var tbody;
- var sortReverse = false;
- var sortIndex;
+ const view = guiList;
- var hostnameFilter, nodeidFilter;
+ let container = null,
+ el = null,
+ tbody = null,
+ sortReverse = false,
+ sortIndex = null,
+ hostnameFilter = null,
+ nodeidFilter = null;
- function sort(a,b){
- function sortNumber(a,b){
- return a - b;
- }
- if(sortIndex === undefined)
- return a.node_id.localeCompare(b.node_id);
- switch (sortIndex.innerHTML) {
- case "Lastseen":
- return a.lastseen - b.lastseen;
- case "CurPower":
- return a._wireless.txpower24 - b._wireless.txpower24;
- case "Power":
- return a.wireless.txpower24 - b.wireless.txpower24;
- case "CurChannel":
- return a._wireless.channel24 - b._wireless.channel24;
- case "Channel":
- return a.wireless.channel24 - b.wireless.channel24;
- case "Clients":
- return a.statistics.clients.wifi24 - b.statistics.clients.wifi24;
- case "ChanUtil":
- var aMax = a.statistics.wireless.map(function(d){
- return d.ChanUtil;
- }).sort(sortNumber);
+ // eslint-disable-next-line id-length
+ function sort (a, b) {
+ function sortNumber (aNum, bNum) {
+ return aNum - bNum;
+ }
+ if (!sortIndex) {
+ return a.node_id.localeCompare(b.node_id);
+ }
+ switch (sortIndex.innerHTML) {
+ case 'Lastseen':
+ return a.lastseen - b.lastseen;
+ case 'CurPower':
+ // eslint-disable-next-line no-underscore-dangle
+ return a._wireless.txpower24 - b._wireless.txpower24;
+ case 'Power':
+ return a.wireless.txpower24 - b.wireless.txpower24;
+ case 'CurChannel':
+ // eslint-disable-next-line no-underscore-dangle
+ return a._wireless.channel24 - b._wireless.channel24;
+ case 'Channel':
+ return a.wireless.channel24 - b.wireless.channel24;
+ case 'Clients':
+ return a.statistics.clients.wifi24 - b.statistics.clients.wifi24;
+ // eslint-disable-next-line no-case-declarations
+ case 'ChanUtil':
+ // eslint-disable-next-line id-length
+ let aMax = a.statistics.wireless.map((d) =>
+ d.ChanUtil
+ ).sort(sortNumber),
+ // eslint-disable-next-line id-length
+ bMax = b.statistics.wireless.map((d) =>
+ d.ChanUtil
+ ).sort(sortNumber);
- var bMax = b.statistics.wireless.map(function(d){
- return d.ChanUtil;
- }).sort(sortNumber);
+ if (!sortReverse) {
+ aMax = aMax.reverse();
+ bMax = bMax.reverse();
+ }
- if(!sortReverse){
- aMax = aMax.reverse();
- bMax = bMax.reverse();
- }
- return bMax[0] - aMax[0];
- case "Hostname":
- return a.hostname.localeCompare(b.hostname);
- default:
- return a.node_id.localeCompare(b.node_id);
- }
- }
+ return bMax[0] - aMax[0];
+ case 'Hostname':
+ return a.hostname.localeCompare(b.hostname);
+ default:
+ return a.node_id.localeCompare(b.node_id);
+ }
+ }
- function renderRow(node){
- var tr = document.createElement('tr');
- var startdate = new Date();
- startdate.setMinutes(startdate.getMinutes() - 1);
- if(new Date(node.lastseen) < startdate)
- tr.classList.add('offline');
+ function renderRow (node) {
+ const startdate = new Date(),
+ tr = document.createElement('tr'),
+ lastseen = domlib.newAt(tr, 'td'),
+ nodeID = domlib.newAt(tr, 'td'),
+ hostname = domlib.newAt(tr, 'td'),
+ freq = domlib.newAt(tr, 'td'),
+ curchannel = domlib.newAt(tr, 'td'),
+ channel = domlib.newAt(tr, 'td'),
+ curpower = domlib.newAt(tr, 'td'),
+ power = domlib.newAt(tr, 'td'),
+ client = domlib.newAt(tr, 'td'),
+ chanUtil = domlib.newAt(tr, 'td'),
+ option = domlib.newAt(tr, 'td'),
+ edit = domlib.newAt(option, 'div');
- domlib.newAt(tr,'td').innerHTML = moment(node.lastseen).fromNow(true);
- domlib.newAt(tr,'td').innerHTML = node.node_id;
+ startdate.setMinutes(startdate.getMinutes() - 1);
+ if (new Date(node.lastseen) < startdate) {
+ tr.classList.add('offline');
+ }
- domlib.newAt(tr,'td').innerHTML = node.hostname;
+ lastseen.innerHTML = moment(node.lastseen).fromNow(true);
- var freq = domlib.newAt(tr,'td');
- domlib.newAt(freq,'span').innerHTML = '2.4 Ghz';
- domlib.newAt(freq,'span').innerHTML = '5 Ghz';
+ nodeID.innerHTML = node.node_id;
- var curchannel = domlib.newAt(tr,'td');
- domlib.newAt(curchannel,'span').innerHTML = node._wireless.channel24||'-';
- domlib.newAt(curchannel,'span').innerHTML = node._wireless.channel5||'-';
+ hostname.innerHTML = node.hostname;
- var channel = domlib.newAt(tr,'td');
- domlib.newAt(channel,'span').innerHTML = node.wireless.channel24||'-';
- domlib.newAt(channel,'span').innerHTML = node.wireless.channel5||'-';
+ domlib.newAt(freq, 'span').innerHTML = '2.4 Ghz';
+ domlib.newAt(freq, 'span').innerHTML = '5 Ghz';
- var curpower = domlib.newAt(tr,'td');
- domlib.newAt(curpower,'span').innerHTML = node._wireless.txpower24||'-';
- domlib.newAt(curpower,'span').innerHTML = node._wireless.txpower5||'-';
+ /* eslint-disable no-underscore-dangle */
+ domlib.newAt(curchannel, 'span').innerHTML = node._wireless.channel24 || '-';
+ domlib.newAt(curchannel, 'span').innerHTML = node._wireless.channel5 || '-';
+ /* eslint-enable no-underscore-dangle */
- var power = domlib.newAt(tr,'td');
- domlib.newAt(power,'span').innerHTML = node.wireless.txpower24||'-';
- domlib.newAt(power,'span').innerHTML = node.wireless.txpower5||'-';
+ domlib.newAt(channel, 'span').innerHTML = node.wireless.channel24 || '-';
+ domlib.newAt(channel, 'span').innerHTML = node.wireless.channel5 || '-';
- var client = domlib.newAt(tr,'td');
- domlib.newAt(client,'span').innerHTML = node.statistics.clients.wifi24;
- domlib.newAt(client,'span').innerHTML = node.statistics.clients.wifi5;
+ /* eslint-disable no-underscore-dangle */
+ domlib.newAt(curpower, 'span').innerHTML = node._wireless.txpower24 || '-';
+ domlib.newAt(curpower, 'span').innerHTML = node._wireless.txpower5 || '-';
+ /* eslint-enable no-underscore-dangle */
- var chanUtil = domlib.newAt(tr,'td');
- var chanUtil24 = node.statistics.wireless.filter(function(d){
- return d.frequency < 5000;
- })[0] || {};
- var chanUtil5 = node.statistics.wireless.filter(function(d){
- return d.frequency > 5000;
- })[0] || {};
- domlib.newAt(chanUtil,'span').innerHTML = chanUtil24.ChanUtil||'-';
- domlib.newAt(chanUtil,'span').innerHTML = chanUtil5.ChanUtil||'-';
+ domlib.newAt(power, 'span').innerHTML = node.wireless.txpower24 || '-';
+ domlib.newAt(power, 'span').innerHTML = node.wireless.txpower5 || '-';
- var option = domlib.newAt(tr,'td');
- var edit = domlib.newAt(option,'div');
- edit.classList.add('btn');
- edit.innerHTML = 'Edit';
- edit.addEventListener('click',function(){
- router.navigate(router.generate('node', { nodeID: node.node_id }));
- });
+ domlib.newAt(client, 'span').innerHTML = node.statistics.clients.wifi24;
+ domlib.newAt(client, 'span').innerHTML = node.statistics.clients.wifi5;
- return tr;
- }
+ /* eslint-disable id-length, no-magic-numbers,one-var */
+ const chanUtil24 = node.statistics.wireless.filter((d) => d.frequency < 5000)[0] || {},
+ chanUtil5 = node.statistics.wireless.filter((d) => d.frequency > 5000)[0] || {};
+ /* eslint-enable id-length, no-magic-numbers,one-var */
- function update(){
- domlib.removeChildren(tbody);
- var nodes = store.getNodes();
+ domlib.newAt(chanUtil, 'span').innerHTML = chanUtil24.ChanUtil || '-';
+ domlib.newAt(chanUtil, 'span').innerHTML = chanUtil5.ChanUtil || '-';
- if(hostnameFilter && hostnameFilter.value != "")
- nodes = nodes.filter(function(d){
- return d.hostname.toLowerCase().indexOf(hostnameFilter.value) > -1;
- });
- if(nodeidFilter && nodeidFilter.value != "")
- nodes = nodes.filter(function(d){
- return d.node_id.indexOf(nodeidFilter.value) > -1;
- });
+ edit.classList.add('btn');
+ edit.innerHTML = 'Edit';
+ edit.addEventListener('click', () => {
+ router.navigate(router.generate('node', {'nodeID': node.node_id}));
+ });
- nodes = nodes.sort(sort);
+ return tr;
+ }
- if(sortReverse)
- nodes = nodes.reverse();
+ function update () {
+ domlib.removeChildren(tbody);
+ let nodes = store.getNodes();
- for(var i=0; i d.hostname.toLowerCase().indexOf(hostnameFilter.value) > -1);
+ }
+ if (nodeidFilter && nodeidFilter.value !== '') {
+ // eslint-disable-next-line id-length
+ nodes = nodes.filter((d) => d.node_id.indexOf(nodeidFilter.value) > -1);
+ }
- function sortTable(head) {
- if(sortIndex)
- sortIndex.classList.remove("sort-up","sort-down");
- sortReverse = head === sortIndex ? !sortReverse : false;
- sortIndex = head;
- sortIndex.classList.add(sortReverse ? 'sort-up' : 'sort-down');
+ nodes = nodes.sort(sort);
- update();
- }
+ if (sortReverse) {
+ nodes = nodes.reverse();
+ }
- view.bind = function(el) {
- container = el;
- };
+ for (let i = 0; i < nodes.length; i += 1) {
+ const row = renderRow(nodes[i]);
- view.render = function(){
- if (container === undefined){
- return;
- } else if (el !== undefined){
- container.appendChild(el);
- update();
- return;
- }
- console.log("generate new view for list");
- el = domlib.newAt(container,'div');
+ tbody.appendChild(row);
+ }
+ }
- var table = domlib.newAt(el,'table');
- var thead = domlib.newAt(table,'thead');
- tbody = domlib.newAt(table,'tbody');
+ function sortTable (head) {
+ if (sortIndex) {
+ sortIndex.classList.remove('sort-up', 'sort-down');
+ }
+ sortReverse = head === sortIndex
+ ? !sortReverse
+ : false;
+ sortIndex = head;
- var tr = domlib.newAt(thead,'tr');
+ sortIndex.classList.add(sortReverse
+ ? 'sort-up'
+ : 'sort-down');
- var cell1 = domlib.newAt(tr,'th');
- cell1.innerHTML = "Lastseen";
- cell1.addEventListener('click', function(){
- sortTable(cell1);
- });
+ update();
+ }
- var cell2 = domlib.newAt(tr,'th');
- cell2.classList.add('sortable');
- nodeidFilter = domlib.newAt(cell2,'input');
- nodeidFilter.setAttribute("placeholder","NodeID");
- nodeidFilter.setAttribute("size","9");
- nodeidFilter.addEventListener('keyup', update);
- cell2.addEventListener('dblclick', function(){
- sortTable(cell2);
- });
+ view.bind = function bind (bindEl) {
+ container = bindEl;
+ };
- var cell3 = domlib.newAt(tr,'th');
- cell3.classList.add('sortable');
- hostnameFilter = domlib.newAt(cell3,'input');
- hostnameFilter.setAttribute("placeholder","Hostname");
- hostnameFilter.addEventListener('keyup', update);
- cell3.addEventListener('dblclick', function(){
- sortTable(cell3);
- });
+ view.render = function render () {
+ if (!container) {
+ return;
+ } else if (el) {
+ container.appendChild(el);
+ update();
- domlib.newAt(tr,'th').innerHTML = 'Freq';
+ return;
+ }
+ console.log('generate new view for list');
+ el = domlib.newAt(container, 'div');
- var cell4 = domlib.newAt(tr,'th');
- cell4.innerHTML = "CurChannel";
- cell4.classList.add('sortable');
- cell4.addEventListener('click', function(){
- sortTable(cell4);
- });
- var cell5 = domlib.newAt(tr,'th');
- cell5.innerHTML = "Channel";
- cell5.classList.add('sortable');
- cell5.addEventListener('click', function(){
- sortTable(cell5);
- });
+ const table = domlib.newAt(el, 'table'),
+ thead = domlib.newAt(table, 'thead');
- var cell6 = domlib.newAt(tr,'th');
- cell6.innerHTML = "CurPower";
- cell6.classList.add('sortable');
- cell6.addEventListener('click', function(){
- sortTable(cell6);
- });
- var cell7 = domlib.newAt(tr,'th');
- cell7.innerHTML = "Power";
- cell7.classList.add('sortable');
- cell7.addEventListener('click', function(){
- sortTable(cell7);
- });
+ tbody = domlib.newAt(table, 'tbody');
- var cell8 = domlib.newAt(tr,'th');
- cell8.innerHTML = "Clients";
- cell8.classList.add('sortable');
- cell8.addEventListener('click', function(){
- sortTable(cell8);
- });
- var cell9 = domlib.newAt(tr,'th');
- cell9.innerHTML = "ChanUtil";
- cell9.classList.add('sortable');
- cell9.addEventListener('click', function(){
- sortTable(cell9);
- });
- domlib.newAt(tr,'th').innerHTML = "Option";
+ // eslint-disable-next-line one-var
+ const tr = domlib.newAt(thead, 'tr'),
+ cell1 = domlib.newAt(tr, 'th'),
+ cell2 = domlib.newAt(tr, 'th'),
+ cell3 = domlib.newAt(tr, 'th'),
+ cell4 = domlib.newAt(tr, 'th'),
+ cell5 = domlib.newAt(tr, 'th'),
+ cell6 = domlib.newAt(tr, 'th'),
+ cell7 = domlib.newAt(tr, 'th'),
+ cell8 = domlib.newAt(tr, 'th'),
+ cell9 = domlib.newAt(tr, 'th'),
+ cell10 = domlib.newAt(tr, 'th'),
+ cell11 = domlib.newAt(tr, 'th');
- table.classList.add('nodes');
+ cell1.innerHTML = 'Lastseen';
+ cell1.addEventListener('click', () => {
+ sortTable(cell1);
+ });
- update();
- };
+ cell2.classList.add('sortable');
+ nodeidFilter = domlib.newAt(cell2, 'input');
+ nodeidFilter.setAttribute('placeholder', 'NodeID');
+ nodeidFilter.setAttribute('size', '9');
+ nodeidFilter.addEventListener('keyup', update);
+ cell2.addEventListener('dblclick', () => {
+ sortTable(cell2);
+ });
+
+
+ cell3.classList.add('sortable');
+ hostnameFilter = domlib.newAt(cell3, 'input');
+ hostnameFilter.setAttribute('placeholder', 'Hostname');
+ hostnameFilter.addEventListener('keyup', update);
+ cell3.addEventListener('dblclick', () => {
+ sortTable(cell3);
+ });
+
+ cell4.innerHTML = 'Freq';
+
+
+ cell5.innerHTML = 'CurChannel';
+ cell5.classList.add('sortable');
+ cell5.addEventListener('click', () => {
+ sortTable(cell4);
+ });
+
+
+ cell6.innerHTML = 'Channel';
+ cell6.classList.add('sortable');
+ cell6.addEventListener('click', () => {
+ sortTable(cell5);
+ });
+
+ cell7.innerHTML = 'CurPower';
+ cell7.classList.add('sortable');
+ cell7.addEventListener('click', () => {
+ sortTable(cell6);
+ });
+
+ cell8.innerHTML = 'Power';
+ cell8.classList.add('sortable');
+ cell8.addEventListener('click', () => {
+ sortTable(cell7);
+ });
+
+
+ cell9.innerHTML = 'Clients';
+ cell9.classList.add('sortable');
+ cell9.addEventListener('click', () => {
+ sortTable(cell8);
+ });
+
+ cell10.innerHTML = 'ChanUtil';
+ cell10.classList.add('sortable');
+ cell10.addEventListener('click', () => {
+ sortTable(cell9);
+ });
+ cell11.innerHTML = 'Option';
+
+ table.classList.add('nodes');
+
+ update();
+ };
})();
diff --git a/webroot/js/gui_map.js b/webroot/js/gui_map.js
index c06f7f8..4ba7c3e 100644
--- a/webroot/js/gui_map.js
+++ b/webroot/js/gui_map.js
@@ -1,148 +1,176 @@
/* exported guiMap */
/* global config,store,domlib,socket */
-var guiMap = {};
+const guiMap = {};
-(function(){
- var view = guiMap;
- var container, el;
+(function init () {
+ 'use strict';
- var geoJsonLayer, nodeLayer, clientLayer24, clientLayer5;//, draggingNodeID;
+ const view = guiMap,
+ WINDOW_HEIGHT_MENU = 50;
- function addNode (node){
- /*
- https://github.com/Leaflet/Leaflet/issues/4484
- if(node.node_id === draggingNodeID){
- return
- }
- */
- if(node.location === undefined || node.location.latitude === undefined || node.location.longitude === undefined) {
- return;
- }
- var className = 'node';
- var startdate = new Date();
- startdate.setMinutes(startdate.getMinutes() - 1);
- if(new Date(node.lastseen) < startdate) {
- className += ' offline';
- }
- var wifi24='-',wifi5='-',ch24='-',ch5='-',tx24='-',tx5='-';
- if(node.statistics && node.statistics.clients){
- wifi24 = node.statistics.clients.wifi24;
+ let container = null,
+ el = null,
- if(wifi24 < config.map.icon.warn.wifi24 && wifi24 > 0){
- className += ' client24';
- } else if(wifi24 < config.map.icon.crit.wifi24 && wifi24 >= config.map.icon.warn.wifi24){
- className += ' client24-warn';
- } else if(wifi24 >= config.map.icon.crit.wifi24){
- className += ' client24-crit';
- }
+ geoJsonLayer = null,
+ nodeLayer = null,
+ clientLayer24 = null,
+ clientLayer5 = null;
+ // , draggingNodeID=null;
- wifi5 = node.statistics.clients.wifi5;
- if(config.map.icon.warn.wifi5 < 20 && wifi5 > 0){
- className += ' client5';
- } else if(wifi5 < config.map.icon.crit.wifi5 && wifi5 >= config.map.icon.warn.wifi5){
- className += ' client5-warn';
- } else if(wifi5 >= config.map.icon.crit.wifi5){
- className += ' client5-crit';
- }
- }
+ function addNode (node) {
+ /* eslint-disable-line https://github.com/Leaflet/Leaflet/issues/4484
+ if(node.node_id === draggingNodeID){
+ return
+ }
+ */
- var nodemarker = L.marker([node.location.latitude, node.location.longitude], {
- icon: L.divIcon({className: className}),
- draggable: true
- });
- nodemarker.bindTooltip(node.hostname+' ('+node.node_id+')'+
- '
'+
- ' | Cl | Ch | Tx |
'+
- '2.4G | '+wifi24+' | '+ch24+' | '+tx24+' |
'+
- '5G | '+wifi5+' | '+ch5+' | '+tx5+' |
'+
- '
'+
- '
'
- );
- /*
- nodemarker.on('dragstart',function(){
- draggingNodeID = node.node_id;
- })
- */
- nodemarker.on('dragend',function(){
- // draggingNodeID = undefined;
- var pos = nodemarker.getLatLng();
- node.location = {
- 'latitude': pos.lat,
- 'longitude': pos.lng
- };
- socket.sendnode(node);
- });
- nodeLayer.addLayer(nodemarker);
- }
+ if (!node.location || !node.location.latitude || !node.location.longitude) {
+ return;
+ }
+ let className = 'node',
+ wifi24 = '-',
+ wifi5 = '-';
+ const startdate = new Date(),
+ ch24 = node.wireless.channel24 || '-',
+ ch5 = node.wireless.channel5 || '-',
+ tx24 = node.wireless.txpower24 || '-',
+ tx5 = node.wireless.txpower5 || '-';
- function update() {
- geoJsonLayer.refresh();
- nodeLayer.clearLayers();
-
- var nodes = store.getNodes();
- for(var i=0; i 0) {
+ className += ' client24';
+ } else if (wifi24 < config.map.icon.crit.wifi24 && wifi24 >= config.map.icon.warn.wifi24) {
+ className += ' client24-warn';
+ } else if (wifi24 >= config.map.icon.crit.wifi24) {
+ className += ' client24-crit';
+ }
+ // eslint-disable-next-line prefer-destructuring
+ wifi5 = node.statistics.clients.wifi5;
- window.addEventListener("resize",function(){
- el.style.height = (window.innerHeight - 50 )+"px";
- map.invalidateSize();
- });
+ if (wifi5 < config.map.icon.warn.wifi5 && wifi5 > 0) {
+ className += ' client5';
+ } else if (wifi5 < config.map.icon.crit.wifi5 && wifi5 >= config.map.icon.warn.wifi5) {
+ className += ' client5-warn';
+ } else if (wifi5 >= config.map.icon.crit.wifi5) {
+ className += ' client5-crit';
+ }
+ }
- update();
- };
+ // eslint-disable-next-line one-var
+ const nodemarker = L.marker([node.location.latitude, node.location.longitude], {
+ 'draggable': true,
+ 'icon': L.divIcon({'className': className})
+ });
+
+ nodemarker.bindTooltip(`${node.hostname} (${node.node_id})` +
+ '
' +
+ ' | Cl | Ch | Tx |
' +
+ `2.4G | ${wifi24} | ${ch24} | ${tx24} |
` +
+ `5G | ${wifi5} | ${ch5} | ${tx5} |
` +
+ '
' +
+ '
'
+ );
+
+ /*
+ Nodemarker.on('dragstart',function(){
+ draggingNodeID = node.node_id;
+ })
+ */
+ nodemarker.on('dragend', () => {
+ // DraggingNodeID = undefined;
+ const pos = nodemarker.getLatLng();
+
+ node.location = {
+ 'latitude': pos.lat,
+ 'longitude': pos.lng
+ };
+ socket.sendnode(node);
+ });
+ nodeLayer.addLayer(nodemarker);
+ }
+
+ function update () {
+ geoJsonLayer.refresh();
+ nodeLayer.clearLayers();
+
+ const nodes = store.getNodes();
+
+ for (let i = 0; i < nodes.length; i += 1) {
+ addNode(nodes[i]);
+ }
+
+
+ clientLayer24.setData(nodes.map((node) => {
+ if (!node.location || !node.location.latitude || !node.location.longitude) {
+ return null;
+ }
+
+ return [node.location.latitude, node.location.longitude, node.statistics.clients.wifi24 || 0];
+ }));
+
+ clientLayer5.setData(nodes.map((node) => {
+ if (!node.location || !node.location.latitude || !node.location.longitude) {
+ return null;
+ }
+
+ return [node.location.latitude, node.location.longitude, node.statistics.clients.wifi5 || 0];
+ }));
+ }
+
+ view.bind = function bind (bindEl) {
+ container = bindEl;
+ };
+
+ view.render = function render () {
+ if (!container) {
+ return;
+ } else if (el) {
+ container.appendChild(el);
+ update();
+
+ return;
+ }
+ console.log('generate new view for map');
+ el = domlib.newAt(container, 'div');
+
+ el.style.height = `${window.innerHeight - WINDOW_HEIGHT_MENU}px`;
+
+ const map = L.map(el).setView(config.map.view.bound, config.map.view.zoom),
+ layerControl = L.control.layers().addTo(map);
+
+ L.tileLayer(config.map.tileLayer, {
+ 'maxZoom': config.map.maxZoom
+ }).addTo(map);
+
+
+ geoJsonLayer = L.geoJson.ajax(config.map.geojson.url, config.map.geojson);
+
+ nodeLayer = L.layerGroup();
+ /* eslint-disable new-cap */
+ clientLayer24 = new L.webGLHeatmap(config.map.heatmap.wifi24);
+ clientLayer5 = new L.webGLHeatmap(config.map.heatmap.wifi5);
+ /* eslint-enable new-cap */
+ layerControl.addOverlay(geoJsonLayer, 'geojson');
+ layerControl.addOverlay(nodeLayer, 'Nodes');
+ layerControl.addOverlay(clientLayer24, 'Clients 2.4 Ghz');
+ layerControl.addOverlay(clientLayer5, 'Clients 5 Ghz');
+ nodeLayer.addTo(map);
+
+ window.addEventListener('resize', () => {
+ el.style.height = `${window.innerHeight - WINDOW_HEIGHT_MENU}px`;
+ map.invalidateSize();
+ });
+
+ update();
+ };
})();
diff --git a/webroot/js/gui_node.js b/webroot/js/gui_node.js
index 6b5d35b..e7ce11e 100644
--- a/webroot/js/gui_node.js
+++ b/webroot/js/gui_node.js
@@ -1,142 +1,179 @@
/* exported guiNode */
/* globals store, socket, domlib, config,notify */
-var guiNode = {};
-(function(){
- var view = guiNode;
- var container, el;
+const guiNode = {};
- var titleName,titleID,ago;
- var marker, map, geoJsonLayer;
- var btnGPS, editLocationGPS, storePosition;
- var current_node_id, editing = false;
+(function init () {
+ 'use strict';
- function updatePosition(lat, lng){
- if(!lat || !lng) {
- lat = storePosition.latitude || false;
- lng = storePosition.longitude || false;
- if(!lat || !lng)
- return;
- }
- var node = store.getNode(current_node_id);
- node.location = {latitude:lat,longitude:lng};
- socket.sendnode(node);
- }
+ const view = guiNode;
- function update(){
- geoJsonLayer.refresh();
- titleID.innerHTML = current_node_id;
- var node = store.getNode(current_node_id);
- if(node === undefined){
- console.log("node not found: "+current_node_id);
- return;
- }
- var startdate = new Date();
- startdate.setMinutes(startdate.getMinutes() - 1);
- if(new Date(node.lastseen) < startdate){
- ago.classList.add('offline');
- ago.classList.remove('online');
- }else{
- ago.classList.remove('offline');
- ago.classList.add('online');
- }
- ago.innerHTML = moment(node.lastseen).fromNow() + ' ('+node.lastseen+')';
- if(editLocationGPS || editing || node.location === undefined || node.location.latitude === undefined || node.location.longitude === undefined) {
- return;
- }
- titleName.innerHTML = node.hostname;
- var latlng = [node.location.latitude,node.location.longitude];
- map.setView(latlng);
- marker.setLatLng(latlng);
- marker.setOpacity(1);
- }
+ let container = null,
+ el = null,
- view.setNodeID = function (nodeID){
- current_node_id = nodeID;
- };
+ titleName = null,
+ titleID = null,
+ ago = null,
- view.bind = function(el) {
- container = el;
- };
- view.render = function render(){
- if (container === undefined){
- return;
- } else if (el !== undefined){
- container.appendChild(el);
- update();
- return;
- }
- console.log("generate new view for node");
- el = domlib.newAt(container,'div');
+ marker = null,
+ map = null,
+ geoJsonLayer = null,
+ btnGPS = null,
- var title = domlib.newAt(el,'h1');
- titleName = domlib.newAt(title,'span');
- title.appendChild(document.createTextNode(" - "));
- titleID = domlib.newAt(title,'i');
+ editLocationGPS = null,
+ storePosition = null,
+ currentNodeID = null,
+ editing = false;
- var lastseen = domlib.newAt(el,'p');
- domlib.newAt(lastseen,'span').innerHTML = "Lastseen: ";
- ago = domlib.newAt(lastseen,'span');
+ function updatePosition (lat, lng) {
+ const node = store.getNode(currentNodeID),
+ newLat = lat || storePosition.latitude || false,
+ newlng = lng || storePosition.longitude || false;
- var mapEl = domlib.newAt(el,'div');
- mapEl.style.height = '300px';
- map = L.map(mapEl).setView(config.map.view.bound, config.map.view.zoom);
+ if (!newLat || !newlng) {
+ return;
+ }
- L.tileLayer(config.map.tileLayer, {
- maxZoom: config.map.maxZoom,
- }).addTo(map);
- geoJsonLayer = L.geoJson.ajax(config.map.geojson.url, config.map.geojson).addTo(map);
+ node.location = {
+ 'latitude': newLat,
+ 'longitude': newlng
+ };
+ socket.sendnode(node);
+ }
- marker = L.marker(config.map.view.bound,{draggable:true,opacity:0.5}).addTo(map);
- marker.on('dragstart', function(){
- editing = true;
- });
- marker.on('dragend', function(){
- editing = false;
- var pos = marker.getLatLng();
- updatePosition(pos.lat,pos.lng);
- });
+ function update () {
+ geoJsonLayer.refresh();
+ titleID.innerHTML = currentNodeID;
+ const node = store.getNode(currentNodeID),
+ startdate = new Date();
+
+ if (!node) {
+ console.log(`node not found: ${currentNodeID}`);
+
+ return;
+ }
+
+ startdate.setMinutes(startdate.getMinutes() - 1);
+ if (new Date(node.lastseen) < startdate) {
+ ago.classList.add('offline');
+ ago.classList.remove('online');
+ } else {
+ ago.classList.remove('offline');
+ ago.classList.add('online');
+ }
+ ago.innerHTML = `${moment(node.lastseen).fromNow()} (${node.lastseen})`;
+ if (editLocationGPS || editing || !node.location || !node.location.latitude || !node.location.longitude) {
+ return;
+ }
+ titleName.innerHTML = node.hostname;
+ // eslint-disable-next-line one-var
+ const latlng = [node.location.latitude, node.location.longitude];
+
+ map.setView(latlng);
+ marker.setLatLng(latlng);
+ marker.setOpacity(1);
+ }
+
+ view.setNodeID = function setNodeID (nodeID) {
+ currentNodeID = nodeID;
+ };
+
+ view.bind = function bind (bindEl) {
+ container = bindEl;
+ };
+
+ view.render = function render () {
+ if (!container) {
+ return;
+ } else if (el) {
+ container.appendChild(el);
+ update();
+
+ return;
+ }
+ console.log('generate new view for node');
+ el = domlib.newAt(container, 'div');
+
+ const title = domlib.newAt(el, 'h1'),
+ lastseen = domlib.newAt(el, 'p'),
+ mapEl = domlib.newAt(el, 'div');
+
+ titleName = domlib.newAt(title, 'span');
+ title.appendChild(document.createTextNode(' - '));
+ titleID = domlib.newAt(title, 'i');
- btnGPS = domlib.newAt(el,'span');
- btnGPS.classList.add('btn');
- btnGPS.innerHTML = "Start follow position";
- btnGPS.addEventListener('click',function(){
- if(editLocationGPS){
- if(btnGPS.innerHTML == "Stop following")
- updatePosition();
- btnGPS.innerHTML = "Start follow position";
- navigator.geolocation.clearWatch(editLocationGPS);
- editLocationGPS = false;
- return;
- }
- btnGPS.innerHTML = 'Following position';
- if (navigator.geolocation !== undefined)
- editLocationGPS = navigator.geolocation.watchPosition(
- function geo_success(position) {
- btnGPS.innerHTML = "Stop following";
- storePosition = position.coords;
- var latlng = [position.coords.latitude, position.coords.longitude];
- marker.setLatLng(latlng);
- map.setView(latlng);
- },
- function geo_error(error) {
- switch (error.code) {
- case error.TIMEOUT:
- notify.send("error","Find Location timeout");
- break;
- }
- },
- {
- enableHighAccuracy: true,
- maximumAge: 30000,
- timeout: 27000
- });
- else
- notify.send("error","Browser did not support Location");
- });
+ domlib.newAt(lastseen, 'span').innerHTML = 'Lastseen: ';
+ ago = domlib.newAt(lastseen, 'span');
- update();
- };
+ mapEl.style.height = '300px';
+ map = L.map(mapEl).setView(config.map.view.bound, config.map.view.zoom);
+
+ L.tileLayer(config.map.tileLayer, {
+ 'maxZoom': config.map.maxZoom
+ }).addTo(map);
+
+ geoJsonLayer = L.geoJson.ajax(config.map.geojson.url,
+ config.map.geojson);
+ geoJsonLayer.addTo(map);
+
+ marker = L.marker(config.map.view.bound, {'draggable': true,
+ 'opacity': 0.5}).addTo(map);
+
+ marker.on('dragstart', () => {
+ editing = true;
+ });
+
+ marker.on('dragend', () => {
+ editing = false;
+ const pos = marker.getLatLng();
+
+ updatePosition(pos.lat, pos.lng);
+ });
+
+
+ btnGPS = domlib.newAt(el, 'span');
+ btnGPS.classList.add('btn');
+ btnGPS.innerHTML = 'Start follow position';
+ btnGPS.addEventListener('click', () => {
+ if (editLocationGPS) {
+ if (btnGPS.innerHTML === 'Stop following') {
+ updatePosition();
+ }
+ btnGPS.innerHTML = 'Start follow position';
+ navigator.geolocation.clearWatch(editLocationGPS);
+ editLocationGPS = false;
+
+ return;
+ }
+ btnGPS.innerHTML = 'Following position';
+ if (navigator.geolocation) {
+ editLocationGPS = navigator.geolocation.watchPosition((position) => {
+ btnGPS.innerHTML = 'Stop following';
+ storePosition = position.coords;
+ const latlng = [position.coords.latitude, position.coords.longitude];
+
+ marker.setLatLng(latlng);
+ map.setView(latlng);
+ }, (error) => {
+ switch (error.code) {
+ case error.TIMEOUT:
+ notify.send('error', 'Find Location timeout');
+ break;
+ default:
+ console.error('a navigator geolocation error: ', error);
+ }
+ },
+ {
+ 'enableHighAccuracy': true,
+ 'maximumAge': 30000,
+ 'timeout': 27000
+ });
+ } else {
+ notify.send('error', 'Browser did not support Location');
+ }
+ });
+ update();
+ };
})();
diff --git a/webroot/js/gui_skelView.js b/webroot/js/gui_skelView.js
index f37b0ce..5ec0a92 100644
--- a/webroot/js/gui_skelView.js
+++ b/webroot/js/gui_skelView.js
@@ -1,28 +1,33 @@
/* exported guiSkel */
/* globals domlib */
-var guiSkel = {};
+const guiSkel = {};
-(function(){
- var view = guiSkel;
- var container, el;
+(function init () {
+ 'use strict';
- function update(){
- }
+ const view = guiSkel;
+ let container = null,
+ el = null;
- view.bind = function(el) {
- container = el;
- };
- view.render = function render(){
- if (container === undefined){
- return;
- } else if (el !== undefined){
- container.appendChild(el);
- update();
- return;
- }
- console.log("generate new view for skel");
- el = domlib.newAt(container,'div');
+ function update () {
+ console.warn('Do not run dummies');
+ }
- update();
- };
+ view.bind = function bind (bindEl) {
+ container = bindEl;
+ };
+ view.render = function render () {
+ if (!container) {
+ return;
+ } else if (el) {
+ container.appendChild(el);
+ update();
+
+ return;
+ }
+ console.log('generate new view for skel');
+ el = domlib.newAt(container, 'div');
+
+ update();
+ };
})();
diff --git a/webroot/js/gui_stats.js b/webroot/js/gui_stats.js
index 0e53bf8..c8469c6 100644
--- a/webroot/js/gui_stats.js
+++ b/webroot/js/gui_stats.js
@@ -1,64 +1,74 @@
/* exported guiStats */
/* globals store, domlib */
-var guiStats = {};
+const guiStats = {};
-(function(){
- var view = guiStats;
- var container, el;
+(function init () {
+ 'use strict';
- var nodes, clients, clientsWifi,clientsWifi24, clientsWifi5;
+ const view = guiStats;
- function update(){
- nodes.innerHTML = store.stats.Nodes;
- clients.innerHTML = store.stats.Clients;
- clientsWifi.innerHTML = store.stats.ClientsWifi;
- clientsWifi24.innerHTML = store.stats.ClientsWifi24;
- clientsWifi5.innerHTML = store.stats.ClientsWifi5;
- }
+ let container = null,
+ el = null,
- view.bind = function(el) {
- container = el;
- };
- view.render = function(){
- if (container === undefined){
- return;
- } else if (el !== undefined){
- container.appendChild(el);
- update();
- return;
- }
- console.log("generate new view for stats");
- el = domlib.newAt(container,'div');
- domlib.newAt(el,'h1').innerHTML = "Statistics";
+ nodes = null,
+ clients = null,
+ clientsWifi = null,
+ clientsWifi24 = null,
+ clientsWifi5 = null;
- var table = domlib.newAt(el,'table');
- table.classList.add("stats");
+ function update () {
+ nodes.innerHTML = store.stats.Nodes;
+ clients.innerHTML = store.stats.Clients;
+ clientsWifi.innerHTML = store.stats.ClientsWifi;
+ clientsWifi24.innerHTML = store.stats.ClientsWifi24;
+ clientsWifi5.innerHTML = store.stats.ClientsWifi5;
+ }
- var tr,title;
+ view.bind = function bind (bindEl) {
+ container = bindEl;
+ };
- tr = domlib.newAt(table,'tr');
- title = domlib.newAt(tr,'th');
- title.innerHTML = "Nodes";
- title.setAttribute("colspan","2");
- nodes = domlib.newAt(tr,'td');
+ view.render = function render () {
+ if (!container) {
+ return;
+ } else if (el) {
+ container.appendChild(el);
+ update();
- tr = domlib.newAt(table,'tr');
- title = domlib.newAt(tr,'th');
- title.innerHTML = "Clients";
- title.setAttribute("colspan","2");
- clients = domlib.newAt(tr,'td');
+ return;
+ }
+ console.log('generate new view for stats');
+ el = domlib.newAt(container, 'div');
+ domlib.newAt(el, 'h1').innerHTML = 'Statistics';
- tr = domlib.newAt(table,'tr');
- tr.classList.add("line");
- domlib.newAt(tr,'th').innerHTML = "Wifi";
- domlib.newAt(tr,'th').innerHTML = "2.4 Ghz";
- domlib.newAt(tr,'th').innerHTML = "5 Ghz";
+ const table = domlib.newAt(el, 'table');
- tr = domlib.newAt(table,'tr');
- clientsWifi = domlib.newAt(tr,'td');
- clientsWifi24 = domlib.newAt(tr,'td');
- clientsWifi5 = domlib.newAt(tr,'td');
+ table.classList.add('stats');
- update();
- };
+ let tr = domlib.newAt(table, 'tr'),
+ title = domlib.newAt(tr, 'th');
+
+ title.innerHTML = 'Nodes';
+ title.setAttribute('colspan', '2');
+ nodes = domlib.newAt(tr, 'td');
+
+ tr = domlib.newAt(table, 'tr');
+ title = domlib.newAt(tr, 'th');
+ title.innerHTML = 'Clients';
+ title.setAttribute('colspan', '2');
+ clients = domlib.newAt(tr, 'td');
+
+ tr = domlib.newAt(table, 'tr');
+ tr.classList.add('line');
+ domlib.newAt(tr, 'th').innerHTML = 'Wifi';
+ domlib.newAt(tr, 'th').innerHTML = '2.4 Ghz';
+ domlib.newAt(tr, 'th').innerHTML = '5 Ghz';
+
+ tr = domlib.newAt(table, 'tr');
+ clientsWifi = domlib.newAt(tr, 'td');
+ clientsWifi24 = domlib.newAt(tr, 'td');
+ clientsWifi5 = domlib.newAt(tr, 'td');
+
+ update();
+ };
})();
diff --git a/webroot/js/notify.js b/webroot/js/notify.js
index ccbdbfe..470d3e4 100644
--- a/webroot/js/notify.js
+++ b/webroot/js/notify.js
@@ -1,51 +1,67 @@
/* exported notify */
-var notify = {};
+const notify = {};
-(function(){
- var container;
- var messages = [];
+(function init () {
+ 'use strict';
- if ("Notification" in window) {
- window.Notification.requestPermission();
- }
+ const DELAY_OF_NOTIFY = 15000,
+ MAX_MESSAGE_SHOW = 10,
+ messages = [];
- function removeLast (){
- messages.splice(0, 1);
- if(container!==undefined && container.firstElementChild)
- container.removeChild(container.firstElementChild);
- }
+ let container = null;
- function renderMsg(msg){
- var msgBox = document.createElement('div');
- msgBox.classList.add("notify",msg.type);
- msgBox.innerHTML = msg.text;
- container.appendChild(msgBox);
- msgBox.addEventListener('click', function(){
- container.removeChild(msgBox);
- if (messages.indexOf(msg) !== -1) {
- messages.splice(messages.indexOf(msg), 1);
- }
- });
- }
+ if ('Notification' in window) {
+ window.Notification.requestPermission();
+ }
- window.setInterval(removeLast,15000);
+ function removeLast () {
+ messages.splice(0, 1);
+ if (container && container.firstElementChild) {
+ container.removeChild(container.firstElementChild);
+ }
+ }
- notify.bind = function(el) {
- container = el;
- };
+ function renderMsg (msg) {
+ const msgBox = document.createElement('div');
- notify.send = function(type, text){
- if("Notification" in window && window.Notification.permission === "granted") {
- new window.Notification(text,{body:type,icon:'/img/logo.jpg'});
- return;
- }
- if(messages.length > 10){
- removeLast();
- }
- var msg = {type:type,text:text};
- messages.push(msg);
- renderMsg(msg);
- };
+ msgBox.classList.add('notify', msg.type);
+ msgBox.innerHTML = msg.text;
+ container.appendChild(msgBox);
+ msgBox.addEventListener('click', () => {
+ container.removeChild(msgBox);
+ if (messages.indexOf(msg) !== -1) {
+ messages.splice(messages.indexOf(msg), 1);
+ }
+ });
+ }
+ window.setInterval(removeLast, DELAY_OF_NOTIFY);
+
+ notify.bind = function bind (el) {
+ container = el;
+ };
+
+ notify.send = function send (type, text) {
+ if ('Notification' in window &&
+ window.Notification.permission === 'granted') {
+ // eslint-disable-next-line no-new
+ new window.Notification(text, {
+ 'body': type,
+ 'icon': '/img/logo.jpg'
+ });
+
+ return;
+ }
+ if (messages.length > MAX_MESSAGE_SHOW) {
+ removeLast();
+ }
+ const msg = {
+ 'text': text,
+ 'type': type
+ };
+
+ messages.push(msg);
+ renderMsg(msg);
+ };
})();
diff --git a/webroot/js/socket.js b/webroot/js/socket.js
index 27c074c..893139d 100644
--- a/webroot/js/socket.js
+++ b/webroot/js/socket.js
@@ -1,64 +1,77 @@
/* exported socket */
-/*globals notify,gui,store,config*/
-var socket = {readyState:0};
+/* globals notify,gui,store,config*/
+let socket = {'readyState': 0};
-(function(){
+(function init () {
+ 'use strict';
- function onerror(err) {
- console.warn(err);
- if(socket.readyState !== 3){
- notify.send("error","Es gibt Übertragungsprobleme!");
- gui.render();
- }
- }
+ const RECONNECT_AFTER = 5000;
- function onopen() {
- gui.render();
- }
+ function onerror (err) {
+ console.warn(err);
+ // eslint-disable-next-line no-magic-numbers
+ if (socket.readyState !== 3) {
+ notify.send('error', 'Es gibt Übertragungsprobleme!');
+ gui.render();
+ }
+ }
- function onmessage(e) {
- var msg = JSON.parse(e.data);
- switch (msg.type) {
- case "current":
- store.updateNode(msg.node,true);
- break;
- case "to-update":
- store.updateNode(msg.node);
- break;
- case "stats":
- if(msg.body) {
- store.stats = msg.body;
- }
- break;
- default:
- notify.send("warn","unable to identify message: "+e);
- break;
- }
- gui.render();
- }
+ function onopen () {
+ gui.render();
+ }
- function onclose(){
- console.log("socket closed by server");
- notify.send("warn","Es besteht ein Verbindungsproblem!");
- gui.render();
- window.setTimeout(connect, 5000);
- }
+ function onmessage (raw) {
+ const msg = JSON.parse(raw.data);
- function sendnode(node) {
- var msg = {type:"to-update",node:node};
- var string = JSON.stringify(msg);
- socket.send(string);
- notify.send("success","Node '"+node.node_id+"' mit neuen Werten wurde übermittelt.");
- }
+ switch (msg.type) {
+ case 'current':
+ store.updateNode(msg.node, true);
+ break;
+ case 'to-update':
+ store.updateNode(msg.node);
+ break;
+ case 'stats':
+ if (msg.body) {
+ store.stats = msg.body;
+ }
+ break;
+ default:
+ notify.send('warn', `unable to identify message: ${raw}`);
+ break;
+ }
+ gui.render();
+ }
- function connect() {
- socket = new window.WebSocket(config.backend);
- socket.onopen = onopen;
- socket.onerror = onerror;
- socket.onmessage = onmessage;
- socket.onclose = onclose;
- socket.sendnode = sendnode;
- }
+ function onclose () {
+ console.log('socket closed by server');
+ notify.send('warn', 'Es besteht ein Verbindungsproblem!');
+ gui.render();
+ // eslint-disable-next-line no-use-before-define
+ window.setTimeout(connect, RECONNECT_AFTER);
+ }
- connect();
+ function sendnode (node) {
+ const notifyMsg = `Einstellungen für '${node.node_id}' gespeichert.`,
+ socketMsg = JSON.stringify({
+ 'node': node,
+ 'type': 'to-update'
+ });
+
+
+ socket.send(socketMsg);
+
+
+ notify.send('success', notifyMsg);
+ }
+
+ function connect () {
+ socket = new window.WebSocket(config.backend);
+ socket.onopen = onopen;
+ socket.onerror = onerror;
+ socket.onmessage = onmessage;
+ socket.onclose = onclose;
+ socket.sendnode = sendnode;
+ }
+
+ connect();
})();
diff --git a/webroot/js/store.js b/webroot/js/store.js
index b7a2959..858296d 100644
--- a/webroot/js/store.js
+++ b/webroot/js/store.js
@@ -1,38 +1,52 @@
/* exported store */
-var store = {
- _list:{},
- _toupdate:{},
- stats:{"Clients":0,"ClientsWifi":0,"ClientsWifi24":0,"ClientsWifi5":0,"Gateways":0,"Nodes":0,"Firmwares":{},"Models":{}}
+
+const store = {
+ 'stats': {
+ 'Clients': 0,
+ 'ClientsWifi': 0,
+ 'ClientsWifi24': 0,
+ 'ClientsWifi5': 0,
+ 'Firmwares': {},
+ 'Gateways': 0,
+ 'Models': {},
+ 'Nodes': 0
+ }
};
-(function(){
+(function init () {
+ 'use strict';
- function getNode(nodeid){
- var node;
- if (store._toupdate[nodeid]) {
- node = store._toupdate[nodeid];
- } else if (store._list[nodeid]){
- node = store._list[nodeid];
- }else{
- return;
- }
- node._wireless = store._list[nodeid].wireless;
- return node;
- }
+ const list = {},
+ toupdate = {};
- store.updateNode = function updateReal(node, real){
- if(real){
- store._list[node.node_id] = node;
- }else{
- store._toupdate[node.node_id] = node;
- }
- };
+ function getNode (nodeid) {
+ let node = {};
- store.getNode = getNode;
+ if (toupdate[nodeid]) {
+ node = toupdate[nodeid];
+ } else if (list[nodeid]) {
+ node = list[nodeid];
+ } else {
+ return null;
+ }
+ // eslint-disable-next-line no-underscore-dangle
+ node._wireless = list[nodeid].wireless;
- store.getNodes = function() {
- return Object.keys(store._list).map(getNode);
- };
+ return node;
+ }
+ store.updateNode = function updateNode (node, real) {
+ if (real) {
+ list[node.node_id] = node;
+ } else {
+ toupdate[node.node_id] = node;
+ }
+ };
+
+ store.getNode = getNode;
+
+ store.getNodes = function getNodes () {
+ return Object.keys(list).map(getNode);
+ };
})();