Compare commits

..

1 commit

Author SHA1 Message Date
Milan Pssler 28eacf8a79 router-pics: some indention and cosmetic fixes 2016-07-04 11:58:54 +02:00
32 changed files with 297 additions and 3906 deletions

View file

@ -1,7 +1,7 @@
language: node_js language: node_js
node_js: before_install:
- "lts/*" - gem install sass
- "node" - npm install -g grunt-cli
install: install:
- yarn - npm install
script: node_modules/.bin/grunt script: grunt

View file

@ -17,7 +17,7 @@ module.exports = function (grunt) {
grunt.loadTasks("tasks") grunt.loadTasks("tasks")
grunt.registerTask("default", ["lint", "saveRevision", "copy", "sass", "postcss", "requirejs"]) grunt.registerTask("default", ["bower-install-simple", "lint", "saveRevision", "copy", "sass", "postcss", "requirejs"])
grunt.registerTask("lint", ["eslint"]) grunt.registerTask("lint", ["eslint"])
grunt.registerTask("dev", ["default", "connect:server", "watch"]) grunt.registerTask("dev", ["default", "connect:server", "watch"])
} }

View file

@ -1,8 +1,8 @@
[![Build Status](https://travis-ci.org/hopglass/hopglass.svg?branch=master)](https://travis-ci.org/hopglass/hopglass) [![Build Status](https://travis-ci.org/plumpudding/hopglass.svg?branch=master)](https://travis-ci.org/plumpudding/hopglass)
# HopGlass # HopGlass
HopGlass is a frontend for the [HopGlass Server](https://github.com/hopglass/hopglass-server). HopGlass is a frontend for the [HopGlass Server](https://github.com/plumpudding/hopglass-server).
# Screenshots # Screenshots
@ -14,32 +14,29 @@ HopGlass is a frontend for the [HopGlass Server](https://github.com/hopglass/hop
# Dependencies # Dependencies
- NodeJS - npm
- yarn (recommended) or npm - bower
- grunt-cli
- Sass (>= 3.2)
# Installing dependencies # Installing dependencies
Install npm package-manager. On Debian-like systems run: Install npm package-manager. On Debian-like systems run:
sudo apt-get install nodejs sudo apt-get install npm
**Note:** The official Debian packages for NodeJS are quite old, you might want to check at [NodeSource](https://github.com/nodesource/distributions/blob/master/README.md) for current binaries installable with your distribution's package manager. On Mac you have to install only npm via brew and sass
On Mac you can install nodejs and yarn via brew:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install node brew install node
brew install yarn sudo gem install sass
On Arch Linux you can install nodejs and yarn via pacman:
sudo pacman -S nodejs yarn
Execute these commands on your server as a normal user to prepare the dependencies: Execute these commands on your server as a normal user to prepare the dependencies:
git clone https://github.com/hopglass/hopglass git clone https://github.com/plumpudding/hopglass
cd hopglass cd hopglass
yarn install # or `npm install` npm install
npm install grunt-cli
# Building # Building
@ -55,7 +52,7 @@ Copy `config.json.example` to `build/config.json` and change it to match your co
## dataPath (string/array) ## dataPath (string/array)
`dataPath` can be either a string containing the address of a [HopGlass Server](https://github.com/hopglass/hopglass-server) or an array containing multiple addresses. `dataPath` can be either a string containing the address of a [HopGlass Server](https://github.com/plumpudding/hopglass-server) or an array containing multiple addresses.
Don't forget the trailing slash! Don't forget the trailing slash!
Also, proxying the data through a webserver will allow GZip and thus will greatly reduce bandwidth consumption. Also, proxying the data through a webserver will allow GZip and thus will greatly reduce bandwidth consumption.
It may help with firewall problems too. It may help with firewall problems too.

26
app.js
View file

@ -1,20 +1,20 @@
require.config({ require.config({
baseUrl: "lib", baseUrl: "lib",
paths: { paths: {
"leaflet": "../node_modules/leaflet/dist/leaflet", "leaflet": "../bower_components/leaflet/dist/leaflet",
"leaflet.label": "../node_modules/leaflet-label/dist/leaflet.label", "leaflet.label": "../bower_components/Leaflet.label/dist/leaflet.label",
"leaflet.providers": "../node_modules/leaflet-providers/leaflet-providers", "leaflet.providers": "../bower_components/leaflet-providers/leaflet-providers",
"chroma-js": "../node_modules/chroma-js/chroma.min", "chroma-js": "../bower_components/chroma-js/chroma.min",
"moment": "../node_modules/moment/min/moment-with-locales.min", "moment": "../bower_components/moment/min/moment-with-locales.min",
"tablesort": "../node_modules/tablesort/tablesort.min", "tablesort": "../bower_components/tablesort/tablesort.min",
"tablesort.numeric": "../node_modules/tablesort/src/sorts/tablesort.numeric", "tablesort.numeric": "../bower_components/tablesort/src/sorts/tablesort.numeric",
"d3": "../node_modules/d3/d3.min", "d3": "../bower_components/d3/d3.min",
"numeral": "../node_modules/numeraljs/min/numeral.min", "numeral": "../bower_components/numeraljs/min/numeral.min",
"numeral-intl": "../node_modules/numeraljs/min/languages.min", "numeral-intl": "../bower_components/numeraljs/min/languages.min",
"virtual-dom": "../node_modules/virtual-dom/dist/virtual-dom", "virtual-dom": "../bower_components/virtual-dom/dist/virtual-dom",
"rbush": "../node_modules/rbush/rbush", "rbush": "../bower_components/rbush/rbush",
"helper": "../helper", "helper": "../helper",
"jshashes": "../node_modules/jshashes/hashes" "jshashes": "../bower_components/jshashes/hashes"
}, },
shim: { shim: {
"leaflet.label": ["leaflet"], "leaflet.label": ["leaflet"],

36
bower.json Normal file
View file

@ -0,0 +1,36 @@
{
"name": "HopGlass",
"ignore": [
"node_modules",
"bower_components",
"**/.*",
"test",
"tests"
],
"dependencies": {
"Leaflet.label": "~0.2.1",
"chroma-js": "~0.6.1",
"leaflet": "~0.7.3",
"ionicons": "~2.0.1",
"moment": "~2.9.0",
"requirejs": "~2.1.16",
"tablesort": "https://github.com/tristen/tablesort.git#v3.0.2",
"roboto-slab-fontface": "*",
"es6-shim": "~0.27.1",
"almond": "~0.3.1",
"r.js": "~2.1.16",
"d3": "~3.5.5",
"numeraljs": "~1.5.3",
"roboto-fontface": "~0.3.0",
"virtual-dom": "~2.0.1",
"leaflet-providers": "~1.0.27",
"rbush": "https://github.com/mourner/rbush.git#~1.3.5",
"jshashes": "~1.0.5"
},
"authors": [
"Milan Pässler <me@petabyteboy.de>",
"Nils Schneider <nils@nilsschneider.net>"
],
"license": "AGPL3",
"private": true
}

View file

@ -1,6 +1,6 @@
({ ({
baseUrl: "lib", baseUrl: "lib",
name: "../node_modules/almond/almond", name: "../bower_components/almond/almond",
mainConfigFile: "app.js", mainConfigFile: "app.js",
include: "../app", include: "../app",
wrap: true, wrap: true,

View file

@ -1,62 +1,21 @@
{ {
"dataPath": "https://map.ffdus.de/data/", "dataPath": "https://map.luebeck.freifunk.net/data/",
"siteName": "Freifunk Flingern", "siteName": "Freifunk Lübeck",
"mapSigmaScale": 0.5, "mapSigmaScale": 0.5,
"showContact": true, "showContact": true,
"maxAge": 14, "maxAge": 14,
"mapLayers": [ "mapLayers": [
{ "name": "CartoDB",
"url": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
"config": {
"maxZoom": 18,
"attribution": "&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>, &copy; | <a href=\"https://carto.com/attribution\">CARTO</a>"
}
},
{ {
"name": "OpenStreetMap.HOT" "name": "OpenStreetMap.HOT"
}, },
{ {
"name": "Luftbilder NRW", "name": "Stamen.TonerLite"
"url": "https://www.wms.nrw.de/geobasis/wms_nw_dop?",
"config": {
"maxZoom": 20,
"attribution": "<a href=\"http://www.bezreg-koeln.nrw.de/brk_internet/geobasis/luftbilderzeugnisse/digitale_orthophotos/index.html\">DOP20</a>, Land NRW (2017), Datenlizenz Deutschland - Namensnennung - Version 2.0 (<a href=\"https://www.govdata.de/dl-de/by-2-0\">www.govdata.de/dl-de/by-2-0</a>)",
"format": "image/jpeg",
"layers": "nw_dop_rgb"
}
}
],
"nodeInfos": [
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=1&theme=light&width=600&height=300&var-nodeid={NODE_ID}"
},
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=2&theme=light&width=600&height=500&var-nodeid={NODE_ID}"
},
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=3&theme=light&width=600&height=200&var-nodeid={NODE_ID}"
}
],
"globalInfos": [
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/global?var-job=dus",
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/global?panelId=1&&theme=light&width=800&height=600&var-job=dus"
},
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/global?var-job=dus",
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/global?panelId=8&&theme=light&width=800&height=600&var-job=dus"
}
],
"linkInfos": [
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/links?var-source={SOURCE}&var-target={TARGET}",
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/links?panelId=1&&theme=light&width=800&height=600&var-source={SOURCE}&var-target={TARGET}"
} }
], ],
"siteNames": [ "siteNames": [
{ "site": "dus", "name": "Flingern" } { "site": "ffhl", "name": "Lübeck" },
], { "site": "ffeh", "name": "Entenhausen" },
"hwImg": [ { "site": "ffgt", "name": "Gothamcity" },
{ "thumbnail": "https://cdn.rawgit.com/Moorviper/meshviewer_hwpics/master/nodes/{MODELHASH}.svg", { "site": "ffal", "name": "Atlantis" }
"caption": "Knoten {MODELHASH}"
}
] ]
} }

View file

@ -132,10 +132,9 @@ function attributeEntry(el, label, value) {
var th = document.createElement("th") var th = document.createElement("th")
if (typeof label === "string") if (typeof label === "string")
th.textContent = label th.textContent = label
else {
else
th.appendChild(label) th.appendChild(label)
tr.className = "routerpic"
}
tr.appendChild(th) tr.appendChild(th)

View file

@ -4,8 +4,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
<link rel="stylesheet" href="css/ionicons.min.css"> <link rel="stylesheet" href="css/ionicons.min.css">
<link rel="stylesheet" href="css/roboto-slab/roboto-slab-fontface.css"> <link rel="stylesheet" href="roboto-slab-fontface.css">
<link rel="stylesheet" href="css/roboto/roboto-fontface.css"> <link rel="stylesheet" href="roboto-fontface.css">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script src="vendor/es6-shim/es6-shim.min.js"></script> <script src="vendor/es6-shim/es6-shim.min.js"></script>
<script src="app.js"></script> <script src="app.js"></script>
@ -14,15 +14,5 @@
</script> </script>
</head> </head>
<body> <body>
<div class="loader">
<p>
Lade<br />
<span class="spinner"></span><br />
Karte &amp; Knoten...
</p>
<noscript>
<strong>JavaScript required</strong>
</noscript>
</div>
</body> </body>
</html> </html>

View file

@ -3,14 +3,14 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no"> <meta name="viewport" content="width=device-width, user-scalable=no">
<link rel="stylesheet" href="node_modules/roboto-fontface/css/roboto-slab/roboto-slab-fontface.css"> <link rel="stylesheet" href="bower_components/roboto-slab-fontface/roboto-slab-fontface.css">
<link rel="stylesheet" href="node_modules/roboto-fontface/css/roboto/roboto-fontface.css"> <link rel="stylesheet" href="bower_components/roboto-fontface/roboto-fontface.css">
<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css"> <link rel="stylesheet" href="bower_components/leaflet/dist/leaflet.css">
<link rel="stylesheet" href="node_modules/leaflet-label/dist/leaflet.label.css"> <link rel="stylesheet" href="bower_components/Leaflet.label/dist/leaflet.label.css">
<link rel="stylesheet" href="node_modules/ionicons/css/ionicons.min.css"> <link rel="stylesheet" href="bower_components/ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script src="node_modules/es6-shim/es6-shim.min.js"></script> <script src="bower_components/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/requirejs/require.js" data-main="app"></script> <script src="bower_components/requirejs/require.js" data-main="app"></script>
</head> </head>
<body> <body>
</body> </body>

View file

@ -29,8 +29,8 @@ define(function () {
s += "https://www.gnu.org/licenses/</a>.</p>" s += "https://www.gnu.org/licenses/</a>.</p>"
s += "<p>The source code is available at " s += "<p>The source code is available at "
s += "<a href=\"https://github.com/hopglass/hopglass\">" s += "<a href=\"https://github.com/plumpudding/hopglass\">"
s += "https://github.com/hopglass/hopglass</a>." s += "https://github.com/plumpudding/hopglass</a>."
el.innerHTML = s el.innerHTML = s
} }

View file

@ -1,7 +1,7 @@
define(["d3"], function (d3) { define(["d3"], function (d3) {
var margin = 200 var margin = 200
var NODE_RADIUS = 15 var NODE_RADIUS = 15
var LINE_RADIUS = 7 var LINE_RADIUS = 12
return function (config, linkScale, sidebar, router) { return function (config, linkScale, sidebar, router) {
var self = this var self = this
@ -242,8 +242,7 @@ define(["d3"], function (d3) {
} }
function visibleLinks(d) { function visibleLinks(d) {
return (d.o.isVPN || return (d.source.x > screenRect.left && d.source.x < screenRect.right &&
d.source.x > screenRect.left && d.source.x < screenRect.right &&
d.source.y > screenRect.top && d.source.y < screenRect.bottom) || d.source.y > screenRect.top && d.source.y < screenRect.bottom) ||
(d.target.x > screenRect.left && d.target.x < screenRect.right && (d.target.x > screenRect.left && d.target.x < screenRect.right &&
d.target.y > screenRect.top && d.target.y < screenRect.bottom) d.target.y > screenRect.top && d.target.y < screenRect.bottom)
@ -325,16 +324,13 @@ define(["d3"], function (d3) {
links.forEach(function (d) { links.forEach(function (d) {
var dx = d.target.x - d.source.x var dx = d.target.x - d.source.x
var dy = d.target.y - d.source.y var dy = d.target.y - d.source.y
var a = Math.sqrt(dx * dx + dy * dy) * 2 var a = Math.sqrt(dx * dx + dy * dy)
dx /= a dx /= a
dy /= a dy /= a
var distancex = d.target.x - d.source.x - (10 * dx)
var distancey = d.target.y - d.source.y - (10 * dy)
ctx.beginPath() ctx.beginPath()
ctx.moveTo(d.source.x + dx * nodeRadius, d.source.y + dy * nodeRadius) ctx.moveTo(d.source.x + dx * nodeRadius, d.source.y + dy * nodeRadius)
ctx.lineTo(d.target.x - (distancex / 2) - dx * nodeRadius, d.target.y - (distancey / 2) - dy * nodeRadius) ctx.lineTo(d.target.x - dx * nodeRadius, d.target.y - dy * nodeRadius)
ctx.strokeStyle = d.o.type === "Kabel" ? cableColor : d.color ctx.strokeStyle = d.o.type === "Kabel" ? cableColor : d.color
ctx.globalAlpha = d.o.isVPN ? 0.1 : 0.8 ctx.globalAlpha = d.o.isVPN ? 0.1 : 0.8
ctx.lineWidth = d.o.isVPN ? 1.5 : 2.5 ctx.lineWidth = d.o.isVPN ? 1.5 : 2.5
@ -380,7 +376,6 @@ define(["d3"], function (d3) {
// -- draw clients -- // -- draw clients --
ctx.save() ctx.save()
ctx.beginPath() ctx.beginPath()
if (scale > 0.9)
nodes.filter(visibleNodes).forEach(function (d) { nodes.filter(visibleNodes).forEach(function (d) {
var clients = d.o.node.statistics.clients var clients = d.o.node.statistics.clients
if (clients === 0) if (clients === 0)
@ -475,34 +470,32 @@ define(["d3"], function (d3) {
requestAnimationFrame(redraw) requestAnimationFrame(redraw)
} }
function distance(ax, ay, bx, by) { function distance(a, b) {
return Math.pow(ax - bx, 2) + Math.pow(ay - by, 2) return Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2)
} }
function distancePoint(a, b) { function distancePoint(a, b) {
return Math.sqrt(distance(a.x, a.y, b.x, b.y)) return Math.sqrt(distance(a, b))
} }
function distanceLink(p, a, b) { function distanceLink(p, a, b) {
/* http://stackoverflow.com/questions/849211 */ /* http://stackoverflow.com/questions/849211 */
var bx = b.x - ((b.x - a.x) / 2) var l2 = distance(a, b)
var by = b.y - ((b.y - a.y) / 2)
var l2 = distance(a.x, a.y, bx, by)
if (l2 === 0) if (l2 === 0)
return distance(p.x, p.y, a.x, a.y) return distance(p, a)
var t = ((p.x - a.x) * (bx - a.x) + (p.y - a.y) * (by - a.y)) / l2 var t = ((p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y)) / l2
if (t < 0) if (t < 0)
return distance(p.x, p.y, a.x, a.y) return distance(p, a)
if (t > 1) if (t > 1)
return distance(p.x, p.y, bx, by) return distance(p, b)
return Math.sqrt(distance(p.x, p.y, a.x + t * (bx - a.x), a.y + t * (by - a.y) )) return Math.sqrt(distance(p, { x: a.x + t * (b.x - a.x),
y: a.y + t * (b.y - a.y) }))
} }
function translateXY(d) { function translateXY(d) {
@ -703,15 +696,6 @@ define(["d3"], function (d3) {
linksDict[d.o.id] = d linksDict[d.o.id] = d
}) })
intLinks.forEach(function (d) {
if (linksDict[d.target.o.node_id + "-" + d.source.o.node_id])
return
var obj = { source: d.target, target: d.source, o: { isVPN: d.o.isVPN, type: "dead", id: d.target.o.node_id + "-" + d.source.o.node_id, tq: 1 }, color: "rgba(255, 255, 255, 0.6)" }
intLinks.push(obj)
linksDict[d.target.o.node_id + "-" + d.source.o.node_id] = obj
})
intNodes.forEach(function (d) { intNodes.forEach(function (d) {
d.neighbours = Object.keys(d.neighbours).map(function (k) { d.neighbours = Object.keys(d.neighbours).map(function (k) {
return d.neighbours[k] return d.neighbours[k]

View file

@ -48,9 +48,6 @@ function (chroma, Map, Sidebar, Tabs, Container, Meshstats, Legend, Linklist,
} }
} }
var loader = document.getElementsByClassName("loader")[0]
loader.classList.add("hide")
contentDiv = document.createElement("div") contentDiv = document.createElement("div")
contentDiv.classList.add("content") contentDiv.classList.add("content")
document.body.appendChild(contentDiv) document.body.appendChild(contentDiv)

View file

@ -1,10 +1,8 @@
define(function () { define(function () {
function showStatImg(o, d) { function showStatImg(o, source, target) {
var subst = {} var subst = {}
subst["{SOURCE}"] = d.source.node_id subst["{SOURCE}"] = source
subst["{SOURCE_NAME}"] = d.source.node.nodeinfo.hostname ? d.source.node.nodeinfo.hostname : "unknown" subst["{TARGET}"] = target
subst["{TARGET}"] = d.target.node_id
subst["{TARGET_NAME}"] = d.target.node.nodeinfo.hostname ? d.target.node.nodeinfo.hostname : "unknown"
return showStat(o, subst) return showStat(o, subst)
} }
@ -37,12 +35,15 @@ define(function () {
attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " " + (hw2 != null ? hw2 : "unbekannt")) attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " " + (hw2 != null ? hw2 : "unbekannt"))
el.appendChild(attributes) el.appendChild(attributes)
if (config.linkInfos) if (config.linkInfos) {
var source = d.source.node_id
var target = d.target.node_id
config.linkInfos.forEach( function (linkInfo) { config.linkInfos.forEach( function (linkInfo) {
var h4 = document.createElement("h4") var h4 = document.createElement("h4")
h4.textContent = linkInfo.name h4.textContent = linkInfo.name
el.appendChild(h4) el.appendChild(h4)
el.appendChild(showStatImg(linkInfo, d)) el.appendChild(showStatImg(linkInfo, source, target))
}) })
} }
}
}) })

View file

@ -133,72 +133,14 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
if (!d.flags.online) if (!d.flags.online)
return undefined return undefined
var meshclients = getMeshClients(d)
resetMeshClients(d)
var before = " ("
var after = " in der lokalen Wolke)"
return function (el) { return function (el) {
el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine")) el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"))
el.appendChild(document.createTextNode(before))
el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"))
el.appendChild(document.createTextNode(after))
el.appendChild(document.createElement("br")) el.appendChild(document.createElement("br"))
var span = document.createElement("span") var span = document.createElement("span")
span.classList.add("clients") span.classList.add("clients")
span.textContent = " ".repeat(d.statistics.clients) span.textContent = " ".repeat(d.statistics.clients)
el.appendChild(span) el.appendChild(span)
var spanmesh = document.createElement("span")
spanmesh.classList.add("clientsMesh")
spanmesh.textContent = " ".repeat(meshclients - d.statistics.clients)
el.appendChild(spanmesh)
}
}
function getMeshClients(node) {
var meshclients = 0
if (node.statistics && !isNaN(node.statistics.clients))
meshclients = node.statistics.clients
if (!node)
return 0
if (node.parsed)
return 0
node.parsed = 1
node.neighbours.forEach(function (neighbour) {
if (!neighbour.link.isVPN && neighbour.node)
meshclients += getMeshClients(neighbour.node)
})
return meshclients
}
function resetMeshClients(node) {
if (!node.parsed)
return
node.parsed = 0
node.neighbours.forEach(function (neighbour) {
if (!neighbour.link.isVPN && neighbour.node)
resetMeshClients(neighbour.node)
})
return
}
function showMeshClients(d) {
if (!d.flags.online)
return undefined
var meshclients = getMeshClients(d)
resetMeshClients(d)
return function (el) {
el.appendChild(document.createTextNode(meshclients > 0 ? meshclients : "keine"))
el.appendChild(document.createElement("br"))
} }
} }
@ -218,9 +160,6 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
if (link) { if (link) {
var a = document.createElement("a") var a = document.createElement("a")
if (ip.includes("."))
a.href = "http://" + ip + "/"
else
a.href = "http://[" + ip + "]/" a.href = "http://[" + ip + "]/"
a.textContent = ip a.textContent = ip
el.appendChild(a) el.appendChild(a)
@ -257,15 +196,13 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
bar.style.background = "rgba(255, 50, 50, 0.9)" bar.style.background = "rgba(255, 50, 50, 0.9)"
span.style.background = "rgba(255, 50, 50, 0.6)" span.style.background = "rgba(255, 50, 50, 0.6)"
span.appendChild(bar) span.appendChild(bar)
} } else {
else
{
bar.style.width = (v * 100) + "%" bar.style.width = (v * 100) + "%"
span.appendChild(bar) span.appendChild(bar)
} }
var label = document.createElement("label") var label = document.createElement("label")
label.textContent = +(Math.round(v + "e+2") + "e-2") label.textContent = (v)
span.appendChild(label) span.appendChild(label)
return span return span
@ -298,22 +235,7 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
} }
} }
function createLink(target, router) { function showGateway(d) {
if (!target) return document.createTextNode("unknown")
var unknown = !(target.node)
var text = unknown ? (target.id ? target.id : target) : target.node.nodeinfo.hostname
if (!unknown) {
var link = document.createElement("a")
link.classList.add("hostname-link")
link.href = "#"
link.onclick = router.node(target.node)
link.textContent = text
return link
}
return document.createTextNode(text)
}
function showGateway(d, router) {
var nh var nh
if (dictGet(d.statistics, ["nexthop"])) if (dictGet(d.statistics, ["nexthop"]))
nh = dictGet(d.statistics, ["nexthop"]) nh = dictGet(d.statistics, ["nexthop"])
@ -321,31 +243,13 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
nh = dictGet(d.statistics, ["gateway_nexthop"]) nh = dictGet(d.statistics, ["gateway_nexthop"])
var gw = dictGet(d.statistics, ["gateway"]) var gw = dictGet(d.statistics, ["gateway"])
if (!gw) return null if (gw && !nh)
return function (el) { return gw
var num = 0 if (gw && nh)
while (gw && nh && gw.id !== nh.id && num < 10) { if (gw === nh)
if (num !== 0) el.appendChild(document.createTextNode(" -> ")) return gw
el.appendChild(createLink(nh, router))
num++
if (!nh.node || !nh.node.statistics) break
if (!dictGet(nh.node.statistics, ["gateway"]) || !dictGet(nh.node.statistics, ["gateway"]).id) break
if (dictGet(nh.node.statistics, ["gateway"]).id !== gw.id) break
if (dictGet(nh.node.statistics, ["gateway_nexthop"]))
nh = dictGet(nh.node.statistics, ["gateway_nexthop"])
else if (dictGet(nh.node.statistics, ["nexthop"]))
nh = dictGet(nh.node.statistics, ["nexthop"])
else else
break return nh + " -> ... -> " + gw
}
if (gw && nh && gw.id !== nh.id) {
if (num !== 0) el.appendChild(document.createTextNode(" -> "))
num++
el.appendChild(document.createTextNode("..."))
}
if (num !== 0) el.appendChild(document.createTextNode(" -> "))
el.appendChild(createLink(gw, router))
}
} }
function showPages(d) { function showPages(d) {
@ -389,7 +293,7 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
function showNodeImg(o, model) { function showNodeImg(o, model) {
if (!model) if (!model)
return document.createTextNode("Knotenname") return undefined
var content, caption var content, caption
var modelhash = model.split("").reduce(function(a, b) { var modelhash = model.split("").reduce(function(a, b) {
@ -397,13 +301,16 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
return a & a return a & a
}, 0) }, 0)
if (o.thumbnail) {
content = document.createElement("img") content = document.createElement("img")
content.id = "routerpicture" content.id = "routerpicture"
content.classList.add("nodeImg") content.classList.add("nodeImg")
content.src = o.thumbnail.replace("{MODELHASH}", modelhash) content.src = o.thumbnail.replace("{MODELHASH}", modelhash)
content.onerror = function() { content.onerror = function() {
console.log("picture not found - if you have configured router pictures create an issue at https://github.com/Moorviper/meshviewer_hwpics/issues")
document.getElementById("routerpicdiv").outerHTML = "Knotenname" document.getElementById("routerpicdiv").outerHTML = "Knotenname"
} }
}
if (o.caption) { if (o.caption) {
caption = o.caption.replace("{MODELHASH}", modelhash) caption = o.caption.replace("{MODELHASH}", modelhash)
@ -426,30 +333,39 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
} }
return function(config, el, router, d) { return function(config, el, router, d) {
var attributes = document.createElement("table")
attributes.classList.add("attributes")
if (config.hwImg) {
var top = document.createElement("div") var top = document.createElement("div")
top.id = "routerpicdiv" top.id = "routerpicdiv"
try { try {
if (config.hwImg)
config.hwImg.forEach(function(hwImg) { config.hwImg.forEach(function(hwImg) {
try { try {
top.appendChild(showNodeImg(hwImg, dictGet(d, ["nodeinfo", "hardware", "model"]))) top.appendChild(showNodeImg(hwImg, d.nodeinfo.hardware.model))
} catch (err) { } catch (err) {
console.log(err.message) console.log(err.message)
} }
}) })
else {
var localpic = [] // create fallback-config-data
localpic.push({
thumbnail: "./nodes/{MODELHASH}.svg",
caption: "Knoten {MODELHASH}"
})
localpic.forEach(function(localpic) {
try {
top.appendChild(showNodeImg(localpic, d.nodeinfo.hardware.model))
} catch (err) { } catch (err) {
console.log(err.message) console.log(err.message)
} }
attributeEntry(attributes, top, d.nodeinfo.hostname) })
} else { }
var h2 = document.createElement("h2") } catch (err) {
h2.textContent = d.nodeinfo.hostname console.log(err.message)
el.appendChild(h2)
} }
var attributes = document.createElement("table")
attributes.classList.add("attributes")
attributeEntry(attributes, top, d.nodeinfo.hostname)
attributeEntry(attributes, "Status", showStatus(d)) attributeEntry(attributes, "Status", showStatus(d))
attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null) attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null)
attributeEntry(attributes, "Koordinaten", showGeoURI(d)) attributeEntry(attributes, "Koordinaten", showGeoURI(d))
@ -472,9 +388,9 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
attributeEntry(attributes, "Arbeitsspeicher", showRAM(d)) attributeEntry(attributes, "Arbeitsspeicher", showRAM(d))
attributeEntry(attributes, "IP Adressen", showIPs(d)) attributeEntry(attributes, "IP Adressen", showIPs(d))
attributeEntry(attributes, "Webseite", showPages(d)) attributeEntry(attributes, "Webseite", showPages(d))
attributeEntry(attributes, "Gewähltes Gateway", showGateway(d, router)) attributeEntry(attributes, "Gewähltes Gateway", showGateway(d))
attributeEntry(attributes, "Autom. Updates", showAutoupdate(d)) attributeEntry(attributes, "Autom. Updates", showAutoupdate(d))
attributeEntry(attributes, "Clients", showClients(d), showMeshClients(d)) attributeEntry(attributes, "Clients", showClients(d))
el.appendChild(attributes) el.appendChild(attributes)
@ -531,7 +447,13 @@ define(["moment", "numeral", "tablesort", "tablesort.numeric"],
tr.appendChild(td1) tr.appendChild(td1)
var td2 = document.createElement("td") var td2 = document.createElement("td")
td2.appendChild(createLink(d, router)) 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)
if (!unknown && has_location(d.node)) { if (!unknown && has_location(d.node)) {
var span = document.createElement("span") var span = document.createElement("span")

View file

@ -123,19 +123,10 @@ function (moment, Router, L, GUI, numeral) {
nodes.forEach( function (d) { nodes.forEach( function (d) {
d.neighbours = [] d.neighbours = []
if (d.statistics) {
/*eslint camelcase:0*/
if ("gateway" in d.statistics && d.statistics.gateway in graphnodes)
d.statistics.gateway = {"node": graphnodes[d.statistics.gateway], "id": d.statistics.gateway}
if ("nexthop" in d.statistics && d.statistics.nexthop in graphnodes)
d.statistics.nexthop = {"node": graphnodes[d.statistics.nexthop], "id": d.statistics.nexthop}
if ("gateway_nexthop" in d.statistics && d.statistics.gateway_nexthop in graphnodes)
d.statistics.gateway_nexthop = {"node": graphnodes[d.statistics.gateway_nexthop], "id": d.statistics.gateway_nexthop}
}
}) })
links.forEach( function (d) { links.forEach( function (d) {
if (d.type === "tunnel" || d.vpn) { if (d.type === "tunnel") {
d.type = "VPN" d.type = "VPN"
d.isVPN = true d.isVPN = true
} else if (d.type === "fastd") { } else if (d.type === "fastd") {
@ -157,10 +148,6 @@ function (moment, Router, L, GUI, numeral) {
d.type = "N/A" d.type = "N/A"
d.isVPN = false d.isVPN = false
} }
if (d.isVPN && d.target.node)
d.target.node.flags.uplink = true
var unknown = (d.source.node === undefined) var unknown = (d.source.node === undefined)
if (unknown) { if (unknown) {
d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true }) d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true })

View file

@ -286,7 +286,7 @@ define(["map/clientlayer", "map/labelslayer",
var layers = config.mapLayers.map( function (d) { var layers = config.mapLayers.map( function (d) {
return { return {
"name": d.name, "name": d.name,
"layer": "url" in d ? "layers" in d.config ? L.tileLayer.wms(d.url, d.config) : L.tileLayer(d.url, d.config) : L.tileLayer.provider(d.name) "layer": "url" in d ? L.tileLayer(d.url, d.config) : L.tileLayer.provider(d.name)
} }
}) })

View file

@ -1,12 +1,15 @@
define(["leaflet"], define(["leaflet", "jshashes"],
function (L) { function (L, jsHashes) {
var MD5 = new jsHashes.MD5()
return L.TileLayer.Canvas.extend({ return L.TileLayer.Canvas.extend({
setData: function (d) { setData: function (d) {
this.data = d this.data = d
//pre-calculate start angles //pre-calculate start angles
this.data.all().forEach(function (d) { this.data.all().forEach(function (d) {
d.startAngle = (parseInt(d.node.nodeinfo.node_id.substr(10, 2), 16) / 255) * 2 * Math.PI var hash = MD5.hex(d.node.nodeinfo.node_id)
d.startAngle = (parseInt(hash.substr(0, 2), 16) / 255) * 2 * Math.PI
}) })
this.redraw() this.redraw()
}, },

View file

@ -13,7 +13,7 @@ define(function () {
return d.statistics.clients ? d.statistics.clients : 0 return d.statistics.clients ? d.statistics.clients : 0
})) }))
var totalGateways = sum(Array.from(new Set(d.nodes.all.filter(online).map( function(d) { var totalGateways = sum(Array.from(new Set(d.nodes.all.filter(online).map( function(d) {
return ("gateway" in d.statistics && d.statistics.gateway.id) ? d.statistics.gateway.id : d.statistics.gateway return d.statistics.gateway
}).concat(d.nodes.all.filter( function (d) { }).concat(d.nodes.all.filter( function (d) {
return d.flags.gateway return d.flags.gateway
})))).map(function(d) { })))).map(function(d) {

View file

@ -21,11 +21,7 @@ define(["sorttable", "virtual-dom", "numeral"], function (SortTable, V, numeral)
var headings = [{ name: "Knoten", var headings = [{ name: "Knoten",
sort: function (a, b) { sort: function (a, b) {
var aname = typeof a.nodeinfo.hostname === "string" ? a.nodeinfo.hostname : a.nodeinfo.node_id return a.nodeinfo.hostname.localeCompare(b.nodeinfo.hostname)
var bname = typeof b.nodeinfo.hostname === "string" ? b.nodeinfo.hostname : b.nodeinfo.node_id
if (typeof aname === "string" && typeof bname === "string")
return aname.localeCompare(bname)
return typeof aname === "string" ? 1 : typeof bname === "string" ? -1 : 0
}, },
reverse: false reverse: false
}, },
@ -56,7 +52,7 @@ define(["sorttable", "virtual-dom", "numeral"], function (SortTable, V, numeral)
td1Content.push(V.h("a", { className: aClass.join(" "), td1Content.push(V.h("a", { className: aClass.join(" "),
onclick: router.node(d), onclick: router.node(d),
href: "#!n:" + d.nodeinfo.node_id href: "#"
}, d.nodeinfo.hostname)) }, d.nodeinfo.hostname))
if (has_location(d)) if (has_location(d))

View file

@ -156,11 +156,8 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
if (d === null) if (d === null)
return null return null
if (d.node) if (d in nodeDict)
return d.node.nodeinfo.hostname return nodeDict[d].nodeinfo.hostname
if (d.id)
return d.id
return d return d
}) })
@ -169,11 +166,8 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
if (d === null) if (d === null)
return null return null
if (d.node) if (d in nodeDict)
return d.node.nodeinfo.hostname return nodeDict[d].nodeinfo.hostname
if (d.id)
return d.id
return d return d
}) })
@ -194,8 +188,8 @@ define(["chroma-js", "virtual-dom", "numeral-intl", "filters/genericnode", "verc
fillTable("Koordinaten", geoTable, geoDict.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("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("Autom. Updates", autoTable, autoDict.sort(function (a, b) { return b[1] - a[1] }))
fillTable("Gateway", gwNodesTable, gwNodesDict.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("Gateway", gwClientsTable, gwClientsDict.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("Site", siteTable, siteDict.sort(function (a, b) { return b[1] - a[1] }))
} }

View file

@ -41,7 +41,7 @@ define(["moment", "virtual-dom"], function (moment, V) {
td1Content.push(V.h("a", { className: aClass.join(" "), td1Content.push(V.h("a", { className: aClass.join(" "),
onclick: router.node(d), onclick: router.node(d),
href: "#!n:" + d.nodeinfo.node_id href: "#"
}, d.nodeinfo.hostname)) }, d.nodeinfo.hostname))
if (has_location(d)) if (has_location(d))

View file

@ -1,41 +1,24 @@
{ {
"name": "hopglass", "name": "hopglass",
"version": "1.0.0",
"scripts": { "scripts": {
"test": "node -e \"require('grunt').cli()\" '' clean lint" "test": "node -e \"require('grunt').cli()\" '' clean lint"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^6.3.3", "autoprefixer": "^6.3.3",
"dart-sass": "^1.16.1", "grunt": "^0.4.5",
"grunt": "^1.0.3",
"grunt-check-dependencies": "^0.6.0", "grunt-check-dependencies": "^0.6.0",
"grunt-contrib-clean": "^0.6.0", "grunt-contrib-clean": "^0.6.0",
"grunt-contrib-connect": "^0.8.0", "grunt-contrib-connect": "^0.8.0",
"grunt-contrib-copy": "^0.5.0", "grunt-contrib-copy": "^0.5.0",
"grunt-contrib-cssmin": "^0.12.2", "grunt-contrib-cssmin": "^0.12.2",
"grunt-contrib-requirejs": "^0.4.4", "grunt-contrib-requirejs": "^0.4.4",
"grunt-sass": "^1.1.0",
"grunt-postcss": "^0.7.2",
"grunt-contrib-uglify": "^0.5.1", "grunt-contrib-uglify": "^0.5.1",
"grunt-contrib-watch": "^0.6.1", "grunt-contrib-watch": "^0.6.1",
"grunt-eslint": "^10.0.0", "grunt-eslint": "^10.0.0",
"grunt-git-describe": "^2.3.2", "grunt-bower-install-simple": "^1.1.2",
"grunt-postcss": "^0.7.2", "grunt-git-describe": "^2.3.2"
"grunt-sass": "^3.0.2"
},
"dependencies": {
"almond": "^0.3.3",
"chroma-js": "^0.7.8",
"d3": "^3.5.17",
"ionicons": "^2.0.1",
"leaflet": "^0.7.7",
"leaflet-label": "^0.2.1-0",
"leaflet-providers": "^1.5.0",
"moment": "^2.23.0",
"numeraljs": "^1.5.6",
"rbush": "^1.4.3",
"requirejs": "^2.3.2",
"roboto-fontface": "^0.10.0",
"tablesort": "3.0.2",
"virtual-dom": "^2.1.1"
}, },
"eslintConfig": { "eslintConfig": {
"env": { "env": {

View file

@ -28,7 +28,3 @@ h5 {
h6 { h6 {
font-size: 0.67em; font-size: 0.67em;
} }
.hide {
display: none;
}

View file

@ -1 +1 @@
../node_modules/leaflet-label/dist/leaflet.label.css ../bower_components/Leaflet.label/dist/leaflet.label.css

View file

@ -1 +1 @@
../node_modules/leaflet/dist/leaflet.css ../bower_components/leaflet/dist/leaflet.css

View file

@ -1,23 +0,0 @@
.loader {
color: #000000;
font-size: 1.8em;
line-height: 2;
margin: 30vh auto;
text-align: center;
}
.spinner {
animation: .6s spinner ease-in-out infinite alternate;
border-bottom: 2px solid #000000;
border-radius: 50%;
display: inline-block;
height: 64px;
margin-top: 10px;
width: 64px;
}
@keyframes spinner {
to {
transform: rotate(360deg);
}
}

View file

@ -13,8 +13,7 @@
display: block; display: block;
z-index: 2; z-index: 2;
} }
.nodeheader img .none{
.nodeheader img .none {
display: none; display: none;
} }
@ -34,3 +33,8 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.limit {
min-height: 1px;
max-height: 1px;
}

View file

@ -4,7 +4,6 @@
@import '_leaflet'; @import '_leaflet';
@import '_leaflet.label'; @import '_leaflet.label';
@import '_filters'; @import '_filters';
@import '_loader';
$minscreenwidth: 630pt; $minscreenwidth: 630pt;
$sidebarwidth: 420pt; $sidebarwidth: 420pt;
@ -70,9 +69,8 @@ $buttondistance: 12pt;
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: 'Roboto-Slab', serif; font-family: 'Roboto Slab', serif;
font-size: 11pt; font-size: 11pt;
color: #333;
} }
th.sort-header::selection { th.sort-header::selection {
@ -103,6 +101,11 @@ table th.sort-up:after {
content: '\f104'; content: '\f104';
} }
table.attributes {
top: 1px;
display: block;
}
table.attributes th { table.attributes th {
text-align: left; text-align: left;
font-weight: bold; font-weight: bold;
@ -118,7 +121,7 @@ table.attributes td {
line-height: 1.41em; line-height: 1.41em;
} }
table.attributes tr.routerpic { table.attributes tr:first-child {
max-height: 128px; max-height: 128px;
max-width: 128px; max-width: 128px;
min-width: 128px; min-width: 128px;
@ -127,14 +130,14 @@ table.attributes tr.routerpic {
/*background-color: green;*/ /*background-color: green;*/
} }
table.attributes tr.routerpic td { table.attributes tr:first-child td{
font-weight: bold; font-weight: bold;
/*background-color: red;*/ /*background-color: red;*/
font-size: large; font-size: large;
vertical-align:bottom; vertical-align:bottom;
} }
table.attributes tr.routerpic th { table.attributes tr:first-child th{
font-weight: bold; font-weight: bold;
/*background-color: red;*/ /*background-color: red;*/
font-size: large; font-size: large;
@ -155,6 +158,7 @@ table.attributes tr.routerpic th {
@include shadow(2); @include shadow(2);
background: rgba(255, 255, 255, 0.97); background: rgba(255, 255, 255, 0.97);
border-radius: 2px; border-radius: 2px;
padding-bottom: 30px;
} }
.container.hidden { .container.hidden {
@ -177,13 +181,6 @@ table.attributes tr.routerpic th {
white-space: normal; white-space: normal;
} }
.infobox .clientsMesh {
font-family: "ionicons";
color: #dbdbdb;
word-spacing: -0.2em;
white-space: normal;
}
.infobox { .infobox {
position: relative; position: relative;
padding: 0.25em 0; padding: 0.25em 0;
@ -221,7 +218,6 @@ button {
@include shadow(1); @include shadow(1);
border-radius: 0.9em; border-radius: 0.9em;
background: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.7);
color: #333;
border: none; border: none;
cursor: pointer; cursor: pointer;
height: 1.8em; height: 1.8em;
@ -261,8 +257,6 @@ button.close {
border-radius: 0; border-radius: 0;
color: rgba(0, 0, 0, 0.5); color: rgba(0, 0, 0, 0.5);
font-family: "ionicons"; font-family: "ionicons";
position: absolute;
right: 0;
&:hover { &:hover {
color: #dc0067; color: #dc0067;
@ -364,7 +358,7 @@ table {
position: absolute; position: absolute;
top: $buttondistance; top: $buttondistance;
left: $buttondistance; left: $buttondistance;
padding-bottom: $buttondistance; margin-bottom: $buttondistance;
transition: left 0.5s; transition: left 0.5s;
} }

View file

@ -1,6 +1,6 @@
module.exports = function(grunt) { module.exports = function(grunt) {
grunt.config.merge({ grunt.config.merge({
nodedir: "node_modules", bowerdir: "bower_components",
copy: { copy: {
html: { html: {
options: { options: {
@ -19,21 +19,26 @@ module.exports = function(grunt) {
dest: "build/" dest: "build/"
}, },
vendorjs: { vendorjs: {
src: ["es6-shim/es6-shim.min.js", src: [ "es6-shim/es6-shim.min.js" ],
"es6-shim/es6-shim.map"],
expand: true, expand: true,
cwd: "node_modules/", cwd: "bower_components/",
dest: "build/vendor/" dest: "build/vendor/"
}, },
roboto: { robotoSlab: {
src: [ "fonts/roboto/*", src: [ "fonts/*",
"fonts/roboto-slab/*", "roboto-slab-fontface.css"
"css/roboto/roboto-fontface.css",
"css/roboto-slab/roboto-slab-fontface.css"
], ],
expand: true, expand: true,
dest: "build/", dest: "build/",
cwd: "node_modules/roboto-fontface/" cwd: "bower_components/roboto-slab-fontface"
},
roboto: {
src: [ "fonts/*",
"roboto-fontface.css"
],
expand: true,
dest: "build/",
cwd: "bower_components/roboto-fontface"
}, },
ionicons: { ionicons: {
src: [ "fonts/*", src: [ "fonts/*",
@ -41,20 +46,19 @@ module.exports = function(grunt) {
], ],
expand: true, expand: true,
dest: "build/", dest: "build/",
cwd: "node_modules/ionicons/" cwd: "bower_components/ionicons/"
}, },
leafletImages: { leafletImages: {
src: [ "images/*" ], src: [ "images/*" ],
expand: true, expand: true,
dest: "build/", dest: "build/",
cwd: "node_modules/leaflet/dist/" cwd: "bower_components/leaflet/dist/"
} }
}, },
sass: { sass: {
options: { options: {
sourceMap: true, sourceMap: true,
outputStyle: "compressed", outputStyle: "compressed"
implementation: require("dart-sass")
}, },
dist: { dist: {
files: { files: {
@ -78,18 +82,31 @@ module.exports = function(grunt) {
cssmin: { cssmin: {
target: { target: {
files: { files: {
"build/style.css": [ "node_modules/leaflet/dist/leaflet.css", "build/style.css": [ "bower_components/leaflet/dist/leaflet.css",
"node_modules/leaflet-label/dist/leaflet.label.css", "bower_components/Leaflet.label/dist/leaflet.label.css",
"style.css" "style.css"
] ]
} }
} }
}, },
"bower-install-simple": {
options: {
directory: "<%=bowerdir%>",
color: true,
interactive: false,
production: true
},
"prod": {
options: {
production: true
}
}
},
requirejs: { requirejs: {
compile: { compile: {
options: { options: {
baseUrl: "lib", baseUrl: "lib",
name: "../node_modules/almond/almond", name: "../bower_components/almond/almond",
mainConfigFile: "app.js", mainConfigFile: "app.js",
include: "../app", include: "../app",
wrap: true, wrap: true,
@ -100,6 +117,7 @@ module.exports = function(grunt) {
} }
}) })
grunt.loadNpmTasks("grunt-bower-install-simple")
grunt.loadNpmTasks("grunt-contrib-copy") grunt.loadNpmTasks("grunt-contrib-copy")
grunt.loadNpmTasks("grunt-contrib-requirejs") grunt.loadNpmTasks("grunt-contrib-requirejs")
grunt.loadNpmTasks("grunt-sass") grunt.loadNpmTasks("grunt-sass")

View file

@ -4,6 +4,11 @@ module.exports = function (grunt) {
options: { options: {
install: true install: true
}, },
bower: {
options: {
packageManager: "bower"
}
},
npm: {} npm: {}
}, },
eslint: { eslint: {

3451
yarn.lock

File diff suppressed because it is too large Load diff