Merged feature webpack into develop

master
Keith Irwin 2017-06-23 14:35:28 -04:00
commit db0c5f4d1a
No known key found for this signature in database
GPG Key ID: 378933C743E2BBC0
18 changed files with 17850 additions and 556 deletions

View File

@ -1,7 +1,4 @@
{
"verbose": true,
"ext": "html, js, json, css",
"events": {
"start": "npm run minify"
}
"ext": "html, js, json, css"
}

View File

@ -12,7 +12,9 @@
"debug": "^2.6.6",
"express": "^4.15.2",
"express-validator": "^3.1.3",
"jquery": "^3.2.1",
"kerberos": "0.0.17",
"load-google-maps-api": "^1.0.0",
"mellt": "^1.0.0",
"minifier": "^0.8.1",
"moment": "^2.12.0",
@ -31,7 +33,8 @@
"passport-twitter-token": "^1.3.0",
"request": "^2.81.0",
"slug": "^0.9.1",
"socket.io": "^1.4.4",
"socket.io": "^1.7.4",
"socket.io-client": "^2.0.3",
"xss": "^0.3.3"
},
"devDependencies": {
@ -44,14 +47,16 @@
"karma-mocha": "^1.1.1",
"mocha": "^2.5.3",
"nodemon": "^1.10.2",
"supertest": "^1.2.0"
"supertest": "^1.2.0",
"webpack": "^3.0.0"
},
"scripts": {
"test": "mocha test.js",
"start": "node server.js",
"nodemon": "nodemon --ignore 'static/**/*.min.*' server.js",
"minify": "minify --template .{{filename}}.min.{{ext}} --clean static",
"update": "sudo n stable && sudo npm update --save && sudo npm prune"
"minify": "minify --template .{{filename}}.min.{{ext}} --clean static/css",
"update": "sudo n stable && sudo npm update --save && sudo npm prune",
"build": "./node_modules/.bin/webpack --config webpack.config.js"
},
"repository": "Tracman-org/Server",
"keywords": [

File diff suppressed because one or more lines are too long

17503
static/js/dist/map.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,316 +0,0 @@
'use strict';
/* global $ io google mapuser userid disp noHeader */
// Variables
var map, pano, marker, elevator, newLoc;
const mapElem = document.getElementById('map'),
panoElem = document.getElementById('pano'),
socket = io('//'+window.location.hostname);
function waitForElements(vars,cb){
if ( vars.every(function(v){ return v!==undefined; }) ){
cb();
} else {
setTimeout(waitForElements(vars,cb), 100);
}
}
function onConnect(socket,userid,mapuserid) {
// Can get location
socket.emit('can-get', mapuserid );
console.log("🚹 Receiving updates for",mapuserid);
// Can set location too
if (mapuserid===userid) {
socket.emit('can-set', userid );
console.log("🚹 Sending updates for",userid);
}
}
// socket.io stuff
socket
.on('connect', function(){
console.log("⬆️ Connected!");
waitForElements([mapuser,userid], function() {
onConnect(socket,userid,mapuser._id);
});
})
.on('disconnect', function(){
console.log("⬇️ Disconnected!");
})
.on('error', function (err){
console.error('❌️',err.message);
});
// Parse location
function parseLoc(loc) {
loc.spd = (mapuser.settings.units=='standard')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd);
loc.dir = parseFloat(loc.dir);
loc.lat = parseFloat(loc.lat);
loc.lon = parseFloat(loc.lon);
loc.tim = new Date(loc.tim).toLocaleString();
loc.glatlng = new google.maps.LatLng(loc.lat, loc.lon);
return loc;
}
// Show/hide map if location is set/unset
function toggleMaps(loc) {
if (loc.lat===0&&loc.lon===0) {
$('#map').hide();
$('#pano').hide();
$('#notset').show();
}
else {
$('#map').show();
$('#pano').show();
$('#notset').hide();
}
}
// Toggle maps on page load
$(function() {
toggleMaps(mapuser.last);
});
// Google maps API callback
window.gmapsCb = function() {
//console.log("gmapsCb() called");
// Make sure everything's ready...
waitForElements([mapuser,disp,noHeader], function() {
// Create map
if (disp!=='1') {
//console.log("Creating map...");
map = new google.maps.Map( mapElem, {
center: new google.maps.LatLng( mapuser.last.lat, mapuser.last.lon ),
panControl: false,
scaleControl: mapuser.settings.showScale,
draggable: false,
zoom: mapuser.settings.defaultZoom,
streetViewControl: false,
zoomControlOptions: {position: google.maps.ControlPosition.LEFT_TOP},
mapTypeId: (mapuser.settings.defaultMap=='road')?google.maps.MapTypeId.ROADMAP:google.maps.MapTypeId.HYBRID
});
marker = new google.maps.Marker({
position: { lat:mapuser.last.lat, lng:mapuser.last.lon },
title: mapuser.name,
map: map,
draggable: false
});
map.addListener('zoom_changed',function(){
map.setCenter(marker.getPosition());
});
// Create iFrame logo
if (noHeader!=='0') {
//console.log("Creating iFrame logo...");
const logoDiv = document.createElement('div');
logoDiv.id = 'map-logo';
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
"<span class='text'>Tracman</span></a>";
map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
}
// Create update time block
//console.log("Creating time block...");
const timeDiv = document.createElement('div');
timeDiv.id = 'timestamp';
if (mapuser.last.time) {
timeDiv.innerHTML = 'location updated '+new Date(mapuser.last.time).toLocaleString();
}
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
// Create speed block
if (mapuser.settings.showSpeed) {
//console.log("Creating speed sign...");
const speedSign = document.createElement('div'),
speedLabel = document.createElement('div'),
speedText = document.createElement('div'),
speedUnit = document.createElement('div');
speedLabel.id = 'spd-label';
speedLabel.innerHTML = 'SPEED';
speedText.id = 'spd';
speedText.innerHTML = (mapuser.settings.units=='standard')?(parseFloat(mapuser.last.spd)*2.23694).toFixed():mapuser.last.spd.toFixed();
speedUnit.id = 'spd-unit';
speedUnit.innerHTML = (mapuser.settings.units=='standard')?'m.p.h.':'k.p.h.';
speedSign.id = 'spd-sign';
speedSign.appendChild(speedLabel);
speedSign.appendChild(speedText);
speedSign.appendChild(speedUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(speedSign);
}
// Create altitude block
if (mapuser.settings.showAlt) {
//console.log("Creating altitude sign...");
const elevator = new google.maps.ElevationService,
altitudeSign = document.createElement('div'),
altitudeLabel = document.createElement('div'),
altitudeText = document.createElement('div'),
altitudeUnit = document.createElement('div');
altitudeLabel.id = 'alt-label';
altitudeText.id = 'alt';
altitudeUnit.id = 'alt-unit';
altitudeSign.id = 'alt-sign';
altitudeText.innerHTML = '';
altitudeLabel.innerHTML = 'ALTITUDE';
getAltitude(new google.maps.LatLng(mapuser.last.lat,mapuser.last.lon), elevator, function(alt) {
if (alt) { altitudeText.innerHTML = (mapuser.settings.units=='standard')?(alt*3.28084).toFixed():alt.toFixed(); }
});
altitudeUnit.innerHTML = (mapuser.settings.units=='standard')?'feet':'meters';
altitudeSign.appendChild(altitudeLabel);
altitudeSign.appendChild(altitudeText);
altitudeSign.appendChild(altitudeUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(altitudeSign);
}
}
// Create streetview
if (disp!=='0' && mapuser.settings.showStreetview) {
//console.log("Creating streetview...");
updateStreetView(parseLoc(mapuser.last),10);
}
});
};
// Got location
socket.on('get', function(loc) {
console.log("🌐️ Got location:",loc.lat+", "+loc.lon);
// Parse location
newLoc = parseLoc(loc);
// Update map
if (disp!=='1') {
// Update time
$('#timestamp').text('location updated '+newLoc.tim);
// Update marker and map center
google.maps.event.trigger(map,'resize');
map.setCenter({ lat:newLoc.lat, lng:newLoc.lon });
marker.setPosition({ lat:newLoc.lat, lng:newLoc.lon });
// Update speed
if (mapuser.settings.showSpeed) {
$('#spd').text( newLoc.spd.toFixed() );
}
// Update altitude
if (mapuser.settings.showAlt) {
getAltitude({
lat: newLoc.lat,
lng: newLoc.lon
}, elevator, function(alt) {
if (alt) {
$('#alt').text( (mapuser.settings.units=='standard')?(alt*3.28084).toFixed():alt.toFixed() );
}
});
}
}
// Update street view
if (disp!=='0' && mapuser.settings.showStreetview) {
updateStreetView(newLoc,10);
}
});
// Check altitude
function getAltitude(loc,elev,cb){
//console.log("Getting altitude...");
elev = elev || new google.maps.ElevationService;
elev.getElevationForLocations({
'locations': [loc]
}, function(results, status) {
if (status === google.maps.ElevationStatus.OK && results[0]) {
cb(results[0].elevation);
}
});
}
// Get street view imagery
function getStreetViewData(loc,rad,cb) {
// Ensure that the location hasn't changed
if (loc===newLoc) {
if (!sv) { var sv=new google.maps.StreetViewService(); }
sv.getPanorama({
location: {
lat: loc.lat,
lng: loc.lon
},
radius: rad
}, function(data,status){ switch (status){
// Success
case google.maps.StreetViewStatus.OK:
cb(data);
break;
// No results in that radius
case google.maps.StreetViewStatus.ZERO_RESULTS:
// Try again with a bigger radius
getStreetViewData(loc,rad*2,cb);
break;
// Error
default:
console.error(new Error('❌️ Street view not available: '+status).message);
} });
} else { console.log('loc!==newLoc'); }
}
// Update streetview
function updateStreetView(loc) {
//console.log("Updating streetview...");
// Moving (show stationary image)
if (loc.spd>1) {
const imgElem = document.getElementById('panoImg');
getStreetViewData(loc, 2, function(data){
if (!imgElem) {
// Create image
pano = undefined;
$('#pano').empty();
$('#pano').append($('<img>',{
alt: 'Street view image',
src: 'https://maps.googleapis.com/maps/api/streetview?size=800x800&location='+loc.lat+','+loc.lon+'&fov=90&heading='+loc.dir+'&key={{api}}',
id: 'panoImg'
}));
}
// Set image
$('#panoImg').attr('src','https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').width()+'x'+$('#pano').height()+'&location='+data.location.latLng.lat()+','+data.location.latLng.lng()+'&fov=90&heading='+loc.dir+'&key={{api}}');
});
}
// Not moving and pano not set (create panoramic image)
else if (pano==null) {
getStreetViewData(loc, 2, function(data){
// Create panorama
$('#pano').empty();
const panoOptions = {
panControl: false,
zoomControl: false,
addressControl: false,
linksControl: false,
motionTracking: false,
motionTrackingControl: false
};
pano = new google.maps.StreetViewPanorama(panoElem, panoOptions);
// Set panorama
pano.setPano(data.location.pano);
pano.setPov({
pitch: 0,
// Point towards users's location from street
heading: Math.atan((loc.lon-data.location.latLng.lng())/(loc.lat-data.location.latLng.lat()))*(180/Math.PI)
});
});
}
}

View File

@ -1,209 +0,0 @@
'use strict';
/**
* Mellt
*
* Tests the strength of a password by calculating how long it would take to
* brute force it.
*
* @version 0.1.0
* @link http://mel.lt/ The homepage for this script.
* @link http://www.hammerofgod.com/passwordcheck.aspx Much of this is based
* on the description of Thor's Godly Privacy password strength checker,
* however the actual code below is all my own.
* @link http://xato.net/passwords/more-top-worst-passwords/ The included
* common passwords list is from Mark Burnett's password collection (which
* is excellent). You can of course use your own password file instead.
*/
var Mellt = function() {
/**
* @var integer HashesPerSecond The number of attempts per second you expect
* an attacker to be able to attempt. Set to 1 billion by default.
*/
this.HashesPerSecond = 1000000000;
/**
* @var string CommonPasswords A variable containing an array of common
* passwords to check against. If you include common-passwords.js in your
* HTML after including Mellt.js, the contents of that file will be used
* if this isn't set.
* Set this to null (and don't include common-passwords.js) to skip
* checking common passwords.
*/
this.CommonPasswords = null;
/**
* @var array $CharacterSets An array of strings, each string containing a
* character set. These should proceed in the order of simplest (0-9) to most
* complex (all characters). More complex = more characters.
*/
this.CharacterSets = [
// We're making some guesses here about human nature (again much of this is
// based on the TGP password strength checker, and Timothy "Thor" Mullen
// deserves the credit for the thinking behind this). Basically we're combining
// what we know about users (SHIFT+numbers are more common than other
// punctuation for example) combined with how an attacker will attack a
// password (most common letters first, expanding outwards).
//
// If you want to support passwords that use non-english characters, and
// your attacker knows this (for example, a Russian site would be expected
// to contain passwords in Russian characters) add your characters to one of
// the sets below, or create new sets and insert them in the right places.
"0123456789",
"abcdefghijklmnopqrstuvwxyz",
"abcdefghijklmnopqrstuvwxyz0123456789",
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+",
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]\"{}|;':,./<>?`~"
];
};
Mellt.prototype = {
CommonPasswords: null,
/**
* Tests password strength by simulating how long it would take a cracker to
* brute force your password.
*
* Also optionally tests against a list of common passwords (contained in an
* external file) to weed out things like "password", which from a pure brute
* force perspective would be harder to break if it wasn't so common.
*
* The character sets being used in this checker assume English (ASCII)
* characters (no umlauts for example). If you run a non-english site, and you
* suspect the crackers will realize this, you may want to modify the
* character set to include the characters in your language.
*
* @param string $password The password to test the strength of
* @return integer Returns an integer specifying how many days it would take
* to brute force the password (at 1 billion checks a second) or -1 to
* indicate the password was found in the common passwords file. Obviously if
* they don't have direct access to the hashed passwords this time would be
* longer, and even then most computers (at the time of this writing) won't be
* able to test 1 billion hashes a second, but this function measures worst
* case scenario, so... I would recommend you require at least 30 days to brute
* force a password, obviously more if you're a bank or other secure system.
* @throws Exception If an error is encountered.
*/
CheckPassword: function(password) {
// First check passwords in the common password file if available.
// We do this because "password" takes 129 seconds, but is the first
// thing an attacker will try.
if (!this.CommonPasswords && Mellt.prototype.CommonPasswords) {
this.CommonPasswords = Mellt.prototype.CommonPasswords;
}
if (this.CommonPasswords) {
var text = password.toLowerCase();
for (var t=0; t<this.CommonPasswords.length; t++) {
if (this.CommonPasswords[t]==text) {
// If their password exists in the common file, then it's
// zero time to crack this terrible password.
return -1;
}
}
}
// Figure out which character set the password is using (based on the most
// "complex" character in it).
var base = '';
var baseKey = null;
for (var t=0; t<password.length; t++) {
var char = password[t];
var foundChar = false;
for (var characterSetKey=0; characterSetKey<this.CharacterSets.length; characterSetKey++) {
var characterSet = this.CharacterSets[characterSetKey];
if (baseKey<=characterSetKey && characterSet.indexOf(char)>-1) {
baseKey = characterSetKey;
base = characterSet;
foundChar = true;
break;
}
}
// If the character we were looking for wasn't anywhere in any of the
// character sets, assign the largest (last) character set as default.
if (!foundChar) {
base = this.CharacterSets[this.CharacterSets.length-1];
break;
}
}
// Starting at the first character, figure out it's position in the character set
// and how many attempts will take to get there. For example, say your password
// was an integer (a bank card PIN number for example):
// 0 (or 0000 if you prefer) would be the very first password they attempted by the attacker.
// 9999 would be the last password they attempted (assuming 4 characters).
// Thus a password/PIN of 6529 would take 6529 attempts until the attacker found
// the proper combination. The same logic words for alphanumeric passwords, just
// with a larger number of possibilities for each position in the password. The
// key thing to note is the attacker doesn't need to test the entire range (every
// possible combination of all characters) they just need to get to the point in
// the list of possibilities that is your password. They can (in this example)
// ignore anything between 6530 and 9999. Using this logic, 'aaa' would be a worse
// password than 'zzz', because the attacker would encounter 'aaa' first.
var attempts = 0;
var charactersInBase = base.length;
var charactersInPassword = password.length;
for (var position=0; position<charactersInPassword; position++) {
// We power up to the reverse position in the string. For example, if we're trying
// to hack the 4 character PING code in the example above:
// First number * (number of characters possible in the charset ^ length of password)
// ie: 6 * (10^4) = 6000
// then add that same equation for the second number:
// 5 * (10^3) = 500
// then the third numbers
// 2 * (10^2) = 20
// and add on the last number
// 9
// Totals: 6000 + 500 + 20 + 9 = 6529 attempts before we encounter the correct password.
var powerOf = charactersInPassword - position - 1;
// Character position within the base set. We add one on because strpos is base
// 0, we want base 1.
var charAtPosition = base.indexOf(password[position])+1;
// If we're at the last character, simply add it's position in the character set
// this would be the "9" in the pin code example above.
if (powerOf==0) {
attempts = attempts + charAtPosition;
}
// Otherwise we need to iterate through all the other characters positions to
// get here. For example, to find the 5 in 25 we can't just guess 2 and then 5
// (even though Hollywood seems to insist this is possible), we need to try 0,1,
// 2,3...15,16,17...23,24,25 (got it).
else {
// This means we have to try every combination of values up to this point for
// all previous characters. Which means we need to iterate through the entire
// character set, X times, where X is our position -1. Then we need to multiply
// that by this character's position.
// Multiplier is the (10^4) or (10^3), etc in the pin code example above.
var multiplier = Math.pow(charactersInBase,powerOf);
// New attempts is the number of attempts we're adding for this position.
var newAttempts = charAtPosition * multiplier;
// Add that on to our existing number of attempts.
attempts = attempts + newAttempts;
}
}
// We can (worst case) try a billion passwords a second. Calculate how many days it
// will take us to get to the password.
var perDay = this.HashesPerSecond*60*60*24;
// This allows us to calculate a number of days to crack. We use days because anything
// that can be cracked in less than a day is basically useless, so there's no point in
// having a smaller granularity (hours for example).
var days = attempts / perDay;
// If it's going to take more than a billion days to crack, just return a billion. This
// helps when code outside this function isn't using bcmath. Besides, if the password
// can survive 2.7 million years it's probably ok.
if (days>1000000000) {
return 1000000000;
}
return Math.round(days);
}
};

View File

@ -2,7 +2,6 @@
/* global navigator $ socket userid token mapuser toggleMaps */
$(function(){
var wpid, newloc;
// Set location

304
static/js/src/map.js Normal file
View File

@ -0,0 +1,304 @@
'use strict';
/* global mapuser userid disp noHeader mapKey */
// Webpack imports
import io from 'socket.io-client';
import $ from 'jquery';
import loadGoogleMapsAPI from 'load-google-maps-api';
// Variables
var map, pano, marker, elevator, newLoc;
const mapElem = document.getElementById('map'),
panoElem = document.getElementById('pano'),
socket = io('//'+window.location.hostname);
// socket.io stuff
socket
.on('connect', function(){
console.log("⬆️ Connected!");
// Can get location
socket.emit('can-get', mapuser._id );
console.log("🚹 Receiving updates for",mapuser._id);
// Can set location too
if (mapuser._id===userid) {
socket.emit('can-set', userid );
console.log("🚹 Sending updates for",userid);
}
})
.on('disconnect', function(){
console.log("⬇️ Disconnected!");
})
.on('error', function (err){
console.error('❌️',err.message);
});
// Show/hide map if location is set/unset
function toggleMaps(loc) {
if (loc.lat===0&&loc.lon===0) {
$('#map').hide();
$('#pano').hide();
$('#notset').show();
}
else {
$('#map').show();
$('#pano').show();
$('#notset').hide();
}
}
// Toggle maps on page load
$(function() {
toggleMaps(mapuser.last);
});
// Load google maps
loadGoogleMapsAPI({ key:mapKey })
.then(function(googlemaps) {
//console.log("Loaded google maps:",googlemaps);
// Create map
if (disp!=='1') {
//console.log("Creating map...");
map = new googlemaps.Map( mapElem, {
center: new googlemaps.LatLng( mapuser.last.lat, mapuser.last.lon ),
panControl: false,
scaleControl: mapuser.settings.showScale,
draggable: false,
zoom: mapuser.settings.defaultZoom,
streetViewControl: false,
zoomControlOptions: {position: googlemaps.ControlPosition.LEFT_TOP},
mapTypeId: (mapuser.settings.defaultMap=='road')?googlemaps.MapTypeId.ROADMAP:googlemaps.MapTypeId.HYBRID
});
marker = new googlemaps.Marker({
position: { lat:mapuser.last.lat, lng:mapuser.last.lon },
title: mapuser.name,
map: map,
draggable: false
});
map.addListener('zoom_changed',function(){
map.setCenter(marker.getPosition());
});
// Create iFrame logo
if (noHeader!=='0') {
//console.log("Creating iFrame logo...");
const logoDiv = document.createElement('div');
logoDiv.id = 'map-logo';
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
"<span class='text'>Tracman</span></a>";
map.controls[googlemaps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
}
// Create update time block
//console.log("Creating time block...");
const timeDiv = document.createElement('div');
timeDiv.id = 'timestamp';
if (mapuser.last.time) {
timeDiv.innerHTML = 'location updated '+new Date(mapuser.last.time).toLocaleString();
}
map.controls[googlemaps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
// Create speed block
if (mapuser.settings.showSpeed) {
//console.log("Creating speed sign...");
const speedSign = document.createElement('div'),
speedLabel = document.createElement('div'),
speedText = document.createElement('div'),
speedUnit = document.createElement('div');
speedLabel.id = 'spd-label';
speedLabel.innerHTML = 'SPEED';
speedText.id = 'spd';
speedText.innerHTML = (mapuser.settings.units=='standard')?(parseFloat(mapuser.last.spd)*2.23694).toFixed():mapuser.last.spd.toFixed();
speedUnit.id = 'spd-unit';
speedUnit.innerHTML = (mapuser.settings.units=='standard')?'m.p.h.':'k.p.h.';
speedSign.id = 'spd-sign';
speedSign.appendChild(speedLabel);
speedSign.appendChild(speedText);
speedSign.appendChild(speedUnit);
map.controls[googlemaps.ControlPosition.TOP_RIGHT].push(speedSign);
}
// Create altitude block
if (mapuser.settings.showAlt) {
//console.log("Creating altitude sign...");
const elevator = new googlemaps.ElevationService,
altitudeSign = document.createElement('div'),
altitudeLabel = document.createElement('div'),
altitudeText = document.createElement('div'),
altitudeUnit = document.createElement('div');
altitudeLabel.id = 'alt-label';
altitudeText.id = 'alt';
altitudeUnit.id = 'alt-unit';
altitudeSign.id = 'alt-sign';
altitudeText.innerHTML = '';
altitudeLabel.innerHTML = 'ALTITUDE';
getAltitude(new googlemaps.LatLng(mapuser.last.lat,mapuser.last.lon), elevator, function(alt) {
if (alt) { altitudeText.innerHTML = (mapuser.settings.units=='standard')?(alt*3.28084).toFixed():alt.toFixed(); }
});
altitudeUnit.innerHTML = (mapuser.settings.units=='standard')?'feet':'meters';
altitudeSign.appendChild(altitudeLabel);
altitudeSign.appendChild(altitudeText);
altitudeSign.appendChild(altitudeUnit);
map.controls[googlemaps.ControlPosition.TOP_RIGHT].push(altitudeSign);
}
}
// Create streetview
if (disp!=='0' && mapuser.settings.showStreetview) {
//console.log("Creating streetview...");
updateStreetView(parseLoc(mapuser.last),10);
}
// Parse location
function parseLoc(loc) {
loc.spd = (mapuser.settings.units=='standard')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd);
loc.dir = parseFloat(loc.dir);
loc.lat = parseFloat(loc.lat);
loc.lon = parseFloat(loc.lon);
loc.tim = new Date(loc.tim).toLocaleString();
loc.glatlng = new googlemaps.LatLng(loc.lat, loc.lon);
return loc;
}
// Got location
socket.on('get', function(loc) {
console.log("🌐️ Got location:",loc.lat+", "+loc.lon);
// Parse location
newLoc = parseLoc(loc);
// Update map
if (disp!=='1') {
// Update time
$('#timestamp').text('location updated '+newLoc.tim);
// Update marker and map center
googlemaps.event.trigger(map,'resize');
map.setCenter({ lat:newLoc.lat, lng:newLoc.lon });
marker.setPosition({ lat:newLoc.lat, lng:newLoc.lon });
// Update speed
if (mapuser.settings.showSpeed) {
$('#spd').text( newLoc.spd.toFixed() );
}
// Update altitude
if (mapuser.settings.showAlt) {
getAltitude({
lat: newLoc.lat,
lng: newLoc.lon
}, elevator, function(alt) {
if (alt) {
$('#alt').text( (mapuser.settings.units=='standard')?(alt*3.28084).toFixed():alt.toFixed() );
}
});
}
}
// Update street view
if (disp!=='0' && mapuser.settings.showStreetview) {
updateStreetView(newLoc,10);
}
});
// Check altitude
function getAltitude(loc,elev,cb){
//console.log("Getting altitude...");
elev = elev || new googlemaps.ElevationService;
elev.getElevationForLocations({
'locations': [loc]
}, function(results, status) {
if (status === googlemaps.ElevationStatus.OK && results[0]) {
cb(results[0].elevation);
}
});
}
// Get street view imagery
function getStreetViewData(loc,rad,cb) {
// Ensure that the location hasn't changed
if (loc===newLoc) {
if (!sv) { var sv=new googlemaps.StreetViewService(); }
sv.getPanorama({
location: {
lat: loc.lat,
lng: loc.lon
},
radius: rad
}, function(data,status){ switch (status){
// Success
case googlemaps.StreetViewStatus.OK:
cb(data);
break;
// No results in that radius
case googlemaps.StreetViewStatus.ZERO_RESULTS:
// Try again with a bigger radius
getStreetViewData(loc,rad*2,cb);
break;
// Error
default:
console.error(new Error('❌️ Street view not available: '+status).message);
} });
} else { console.log('loc!==newLoc'); }
}
// Update streetview
function updateStreetView(loc) {
//console.log("Updating streetview...");
// Moving (show stationary image)
if (loc.spd>1) {
const imgElem = document.getElementById('panoImg');
getStreetViewData(loc, 2, function(data){
if (!imgElem) {
// Create image
pano = undefined;
$('#pano').empty();
$('#pano').append($('<img>',{
alt: 'Street view image',
src: 'https://maps.googleapis.com/maps/api/streetview?size=800x800&location='+loc.lat+','+loc.lon+'&fov=90&heading='+loc.dir+'&key={{api}}',
id: 'panoImg'
}));
}
// Set image
$('#panoImg').attr('src','https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').width()+'x'+$('#pano').height()+'&location='+data.location.latLng.lat()+','+data.location.latLng.lng()+'&fov=90&heading='+loc.dir+'&key={{api}}');
});
}
// Not moving and pano not set (create panoramic image)
else if (pano==null) {
getStreetViewData(loc, 2, function(data){
// Create panorama
$('#pano').empty();
const panoOptions = {
panControl: false,
zoomControl: false,
addressControl: false,
linksControl: false,
motionTracking: false,
motionTrackingControl: false
};
pano = new googlemaps.StreetViewPanorama(panoElem, panoOptions);
// Set panorama
pano.setPano(data.location.pano);
pano.setPov({
pitch: 0,
// Point towards users's location from street
heading: Math.atan((loc.lon-data.location.latLng.lng())/(loc.lat-data.location.latLng.lat()))*(180/Math.PI)
});
});
}
}
}).catch((err) => {
console.error(err);
});

View File

@ -94,27 +94,21 @@
{% block javascript %}
{{super()}}
<!-- require.js -->
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js" integrity="sha256-4FF6zC8o0//sei6CJUD+MJIhewXKgcrV/iA/4HD4A8c=" crossorigin="anonymous"></script>
<!-- socket.io -->
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js" integrity="sha256-WKvqiY0jZHWQZIohYEmr9KUC5rEaYEOFTq+ByllJK8w=" crossorigin="anonymous"></script>
<!-- google maps API -->
<script type="application/javascript" src="https://maps.googleapis.com/maps/api/js?key={{mapApi}}&callback=gmapsCb" async defer></script>
<!-- client-side javascript -->
<script type="application/javascript" src="/static/js/.map.min.js"></script>
{% if user.id == mapuser.id %}
<!-- client-side controls javascript -->
<script type="application/javascript" src="/static/js/.map-controls.min.js"></script>
{% endif %}
<!-- Variables from server-side -->
<script>
const mapuser = JSON.parse('{{mapuser |dump|safe}}'),
mapKey = "{{mapApi |safe}}",
noHeader = "{{noHeader |safe}}",
disp = "{{disp |safe}}", // 0=map, 1=streetview, 2=both
userid = "{{user._id |safe}}",
token = "{{user.sk32 |safe}}";
</script>
<!-- Webpacked bundles -->
<script type="application/javascript" src="/static/js/dist/map.js"></script>
{% if user.id == mapuser.id %}
<script type="application/javascript" src="/static/js/dist/controls.js"></script>
{% endif %}
{% endblock %}

View File

@ -53,7 +53,7 @@
{% block javascript %}
{{super()}}
<script type="application/javascript" src="/static/js/.mellt.min.js"></script>
<script type="application/javascript" src="/static/js/.common-passwords.min.js"></script>
<script type="application/javascript" src="/static/js/.password.min.js"></script>
<script type="application/javascript" src="/static/js/dist/mellt.js"></script>
<script type="application/javascript" src="/static/js/dist/commonpasswords.js"></script>
<script type="application/javascript" src="/static/js/dist/password.js"></script>
{% endblock %}

View File

@ -150,5 +150,5 @@
{% block javascript %}
{{super()}}
<script type="application/javascript" src="/static/js/.settings.min.js"></script>
<script type="application/javascript" src="/static/js/dist/settings.js"></script>
{% endblock %}

View File

@ -9,8 +9,8 @@
<a href="https://cash.me/$KeithIrwin"><i class="fa fa-dollar"></i></a>
<a href="bitcoin:14VN8GzWQPssWQherCE5XNGBWzy3eCDn74?label=tracman"><i class="fa fa-btc"></i></a>
<br>
<a href="/privacy">Privacy Policy</a> <a href="/terms">Terms of Service</a>
<a href="/privacy">Privacy Policy</a> | <a href="/terms">Terms of Service</a>
</div>
</footer>
<script type="application/javascript" src="/static/js/.footer.min.js"></script>
<script type="application/javascript" src="/static/js/dist/footer.js"></script>

View File

@ -56,4 +56,4 @@
</div>
{% endfor %}
<script type="application/javascript" src="/static/js/.header.min.js"></script>
<script type="application/javascript" src="/static/js/dist/header.js"></script>

18
webpack.config.js Normal file
View File

@ -0,0 +1,18 @@
var path = require('path');
module.exports = {
entry: {
header: './static/js/src/header.js',
footer: './static/js/src/footer.js',
map: './static/js/src/map.js',
controls: './static/js/src/map-controls.js',
settings: './static/js/src/settings.js',
password: './static/js/src/password.js',
mellt: './static/js/src/mellt.js',
commonpasswords: './static/js/src/common-passwords.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'static/js/dist')
}
};