Merge develop branch into master for release 0.5.0
commit
564dc54666
15
README.md
15
README.md
|
@ -1,11 +1,11 @@
|
||||||
# Tracman
|
# Tracman
|
||||||
###### v 0.4.3
|
###### v 0.5.0
|
||||||
|
|
||||||
node.js application to display a map with user's location.
|
node.js application to display a map with user's location.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```sh
|
```sh
|
||||||
$ git clone https://github.com/Tracman-org/Server.git && (cd server && exec npm install)
|
$ git clone https://github.com/Tracman-org/Server.git && (cd Server && exec npm install)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
@ -14,8 +14,19 @@ $ git clone https://github.com/Tracman-org/Server.git && (cd server && exec npm
|
||||||
$ npm start
|
$ npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Tracman will be updated according to [this branching model](http://nvie.com/posts/a-successful-git-branching-model).
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
#### v0.5.0
|
||||||
|
|
||||||
|
* Updated libraries
|
||||||
|
* Fixed recognition of attached clients [#34](https://github.com/Tracman-org/Server/issues/21)
|
||||||
|
* Moved socket.io code to own file.
|
||||||
|
* Many minor fixes
|
||||||
|
|
||||||
#### v0.4.3
|
#### v0.4.3
|
||||||
|
|
||||||
* Fixed memory store [#21](https://github.com/Tracman-org/Server/issues/21)
|
* Fixed memory store [#21](https://github.com/Tracman-org/Server/issues/21)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
var passport = require('passport'),
|
'use strict';
|
||||||
|
|
||||||
|
const passport = require('passport'),
|
||||||
slug = require('slug'),
|
slug = require('slug'),
|
||||||
crypto = require('crypto'),
|
crypto = require('crypto'),
|
||||||
secret = require('./secrets.js'),
|
secret = require('./secrets.js'),
|
||||||
|
@ -30,7 +32,7 @@ passport.use(new GoogleStrategy({
|
||||||
|
|
||||||
// User not found
|
// User not found
|
||||||
else /* create user */ {
|
else /* create user */ {
|
||||||
var user = new User();
|
user = new User();
|
||||||
user.googleID = profile.id;
|
user.googleID = profile.id;
|
||||||
user.name = profile.displayName;
|
user.name = profile.displayName;
|
||||||
user.email = profile.emails[0].value;
|
user.email = profile.emails[0].value;
|
||||||
|
@ -42,7 +44,7 @@ passport.use(new GoogleStrategy({
|
||||||
// user.isPro = false;
|
// user.isPro = false;
|
||||||
// user.isAdmin = false;
|
// user.isAdmin = false;
|
||||||
var cbc = 2;
|
var cbc = 2;
|
||||||
var successMessage, failMessage
|
var successMessage, failMessage;
|
||||||
|
|
||||||
// Generate slug
|
// Generate slug
|
||||||
(function checkSlug(s,cb) {
|
(function checkSlug(s,cb) {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
var secret = require('./secrets.js');
|
'use strict';
|
||||||
|
|
||||||
|
const secret = require('./secrets.js');
|
||||||
|
|
||||||
var throwErr = function(req,err){
|
var throwErr = function(req,err){
|
||||||
console.log('middleware.js:5 '+typeof err);
|
console.log('middleware.js:5 '+typeof err);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
var mongoose = require('mongoose');
|
'use strict';
|
||||||
|
|
||||||
module.exports = mongoose.model('User', {
|
const mongoose = require('mongoose');
|
||||||
|
|
||||||
|
const userSchema = new mongoose.Schema({
|
||||||
name: {type:String, required:true},
|
name: {type:String, required:true},
|
||||||
email: String,
|
email: String,
|
||||||
slug: {type:String, required:true, unique:true},
|
slug: {type:String, required:true, unique:true},
|
||||||
|
@ -29,3 +31,5 @@ module.exports = mongoose.model('User', {
|
||||||
},
|
},
|
||||||
sk32: {type:String, required:true, unique:true}
|
sk32: {type:String, required:true, unique:true}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('User', userSchema);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
var router = require('express').Router(),
|
'use strict';
|
||||||
|
|
||||||
|
const router = require('express').Router(),
|
||||||
mw = require('../middleware.js'),
|
mw = require('../middleware.js'),
|
||||||
User = require('../models/user.js');
|
User = require('../models/user.js');
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
var router = require('express').Router(),
|
'use strict';
|
||||||
|
|
||||||
|
const router = require('express').Router(),
|
||||||
passport = require('passport');
|
passport = require('passport');
|
||||||
|
|
||||||
router.get('/login', function(req,res){
|
router.get('/login', function(req,res){
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
var router = require('express').Router(),
|
'use strict';
|
||||||
mw = require('../middleware.js'),
|
|
||||||
secret = require('../secrets.js'),
|
|
||||||
User = require('../models/user.js');
|
|
||||||
|
|
||||||
|
const slug = require('slug'),
|
||||||
|
mw = require('../middleware.js'),
|
||||||
|
User = require('../models/user.js'),
|
||||||
|
router = require('express').Router();
|
||||||
|
|
||||||
|
// Shortcut to favicon.ico
|
||||||
|
router.get('/favicon.ico', function(req,res){
|
||||||
|
res.redirect('/static/img/icon/by/16-32-48.ico');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Index route
|
||||||
router.route('/')
|
router.route('/')
|
||||||
.get(function(req,res,next){
|
.get(function(req,res,next){
|
||||||
|
|
||||||
// Logged in
|
// Logged in
|
||||||
if (req.session.passport&&req.session.passport.user) {
|
if ( req.session.passport && req.session.passport.user ){
|
||||||
// Get user
|
// Get user
|
||||||
User.findById(req.session.passport.user, function(err, user){
|
User.findById(req.session.passport.user, function(err, user){
|
||||||
if (err){ mw.throwErr(req,err); }
|
if (err){ mw.throwErr(req,err); }
|
||||||
|
@ -21,9 +29,7 @@ router.route('/')
|
||||||
success: req.flash('succcess')[0]
|
success: req.flash('succcess')[0]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
// Not logged in
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not logged in
|
// Not logged in
|
||||||
|
@ -36,4 +42,55 @@ router.route('/')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
router.route('/settings')
|
||||||
|
|
||||||
|
// Get settings form
|
||||||
|
.get(mw.ensureAuth, function(req,res,next){
|
||||||
|
User.findById(req.session.passport.user, function(err,user){
|
||||||
|
if (err){ console.log('Error finding settings for user:',err); mw.throwErr(req,err); }
|
||||||
|
res.render('settings.html', {user:user});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set new settings
|
||||||
|
}).post(mw.ensureAuth, function(req,res,next){
|
||||||
|
User.findByIdAndUpdate(req.session.passport.user, {$set:{
|
||||||
|
name: req.body.name,
|
||||||
|
slug: slug(req.body.slug),
|
||||||
|
email: req.body.email,
|
||||||
|
settings: {
|
||||||
|
units: req.body.units,
|
||||||
|
defaultMap: req.body.map,
|
||||||
|
defaultZoom: req.body.zoom,
|
||||||
|
showSpeed: (req.body.showSpeed)?true:false,
|
||||||
|
showAlt: (req.body.showAlt)?true:false,
|
||||||
|
showStreetview: (req.body.showStreet)?true:false
|
||||||
|
}
|
||||||
|
}}, function(err, user){
|
||||||
|
if (err) { console.log('Error updating user settings:',err); mw.throwErr(req,err); }
|
||||||
|
else { req.flash('success', 'Settings updated. '); }
|
||||||
|
res.redirect('/map#');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
// Delete user account
|
||||||
|
.delete(mw.ensureAuth, function(req,res,next){
|
||||||
|
User.findByIdAndRemove( req.session.passport.user,
|
||||||
|
function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.log('Error deleting user:',err);
|
||||||
|
mw.throwErr(req,err);
|
||||||
|
} else {
|
||||||
|
req.flash('success', 'Your account has been deleted. ');
|
||||||
|
res.redirect('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.route('/help')
|
||||||
|
.get(mw.ensureAuth, function(req,res){
|
||||||
|
res.render('help.html', {user:req.session.passport.user});
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
|
@ -1,7 +1,8 @@
|
||||||
var router = require('express').Router(),
|
'use strict';
|
||||||
|
|
||||||
|
const router = require('express').Router(),
|
||||||
mw = require('../middleware.js'),
|
mw = require('../middleware.js'),
|
||||||
secret = require('../secrets.js'),
|
secrets = require('../secrets.js'),
|
||||||
slug = require('slug'),
|
|
||||||
User = require('../models/user.js');
|
User = require('../models/user.js');
|
||||||
|
|
||||||
// Show map
|
// Show map
|
||||||
|
@ -44,8 +45,8 @@ router.get('/:slug?', function(req,res,next){
|
||||||
} else {
|
} else {
|
||||||
if (user && !mapuser) { mapuser = user; }
|
if (user && !mapuser) { mapuser = user; }
|
||||||
res.render('map.html', {
|
res.render('map.html', {
|
||||||
api: secret.mapAPI,
|
|
||||||
mapuser: mapuser,
|
mapuser: mapuser,
|
||||||
|
mapApi: secrets.googleMapsAPI,
|
||||||
user: user,
|
user: user,
|
||||||
noFooter: '1',
|
noFooter: '1',
|
||||||
noHeader: (req.query.noheader)?req.query.noheader.match(/\d/)[0]:'',
|
noHeader: (req.query.noheader)?req.query.noheader.match(/\d/)[0]:'',
|
||||||
|
@ -56,49 +57,4 @@ router.get('/:slug?', function(req,res,next){
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/:slug?', mw.ensureAuth, function(req,res,next){
|
|
||||||
// Set new user settings
|
|
||||||
User.findByIdAndUpdate(req.session.passport.user, {$set:{name: req.body.name,
|
|
||||||
slug: slug(req.body.slug),
|
|
||||||
email: req.body.email,
|
|
||||||
settings: {
|
|
||||||
units: req.body.units,
|
|
||||||
defaultMap: req.body.map,
|
|
||||||
defaultZoom: req.body.zoom,
|
|
||||||
showSpeed: (req.body.showSpeed)?true:false,
|
|
||||||
showAlt: (req.body.showAlt)?true:false,
|
|
||||||
showStreetview: (req.body.showStreet)?true:false
|
|
||||||
}
|
|
||||||
}}, function(err, user){
|
|
||||||
if (err) { console.log('Error updating user settings:',err); mw.throwErr(req,err); }
|
|
||||||
else { req.flash('success', 'Settings updated. '); }
|
|
||||||
res.redirect('/map#');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
router.delete('/:slug?', mw.ensureAuth, function(req,res,next){
|
|
||||||
// Delete user account
|
|
||||||
User.findByIdAndRemove(
|
|
||||||
req.session.passport.user,
|
|
||||||
function(err) {
|
|
||||||
if (err) {
|
|
||||||
console.log('Error deleting user:',err);
|
|
||||||
mw.throwErr(req,err);
|
|
||||||
} else {
|
|
||||||
req.flash('success', 'Your account has been deleted. ');
|
|
||||||
res.sendStatus(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Redirect /id/ to /slug/
|
|
||||||
router.get('/id/:id', function(req,res,next){
|
|
||||||
User.findById(req.params.id, function(err, user){
|
|
||||||
if (err){ mw.throwErr(req,err); }
|
|
||||||
if (!user){ next(); }
|
|
||||||
else { res.redirect('/map/'+user.slug+((req.url.indexOf('?')<0)?'':('?'+req.url.split('?')[1]))); }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
|
@ -1,4 +1,6 @@
|
||||||
var router = require('express').Router(),
|
'use strict';
|
||||||
|
|
||||||
|
const router = require('express').Router(),
|
||||||
mw = require('../middleware.js'),
|
mw = require('../middleware.js'),
|
||||||
slug = require('slug'),
|
slug = require('slug'),
|
||||||
User = require('../models/user.js');
|
User = require('../models/user.js');
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
const User = require('./models/user.js');
|
||||||
|
|
||||||
|
// Check for tracking clients
|
||||||
|
function checkForUsers(io, user) {
|
||||||
|
//console.log(`Checking for clients receiving updates for ${user}`);
|
||||||
|
|
||||||
|
// Checks if any sockets are getting updates for this user
|
||||||
|
//TODO: Use Object.values() after upgrading to node v7
|
||||||
|
if (Object.keys(io.sockets.connected).map( function(id){
|
||||||
|
return io.sockets.connected[id];
|
||||||
|
}).some( function(socket){
|
||||||
|
return socket.gets==user;
|
||||||
|
})) {
|
||||||
|
//console.log(`Activating updates for ${user}.`);
|
||||||
|
io.to(user).emit('activate','true');
|
||||||
|
} else {
|
||||||
|
//console.log(`Deactivating updates for ${user}.`);
|
||||||
|
io.to(user).emit('activate', 'false');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
checkForUsers: checkForUsers,
|
||||||
|
|
||||||
|
init: function(io){
|
||||||
|
io.on('connection', function(socket) {
|
||||||
|
//console.log(`${socket.id} connected.`);
|
||||||
|
|
||||||
|
// Log
|
||||||
|
//socket.on('log', function(text){
|
||||||
|
//console.log(`LOG: ${text}`);
|
||||||
|
//});
|
||||||
|
|
||||||
|
// This socket can set location (app)
|
||||||
|
socket.on('can-set', function(userId){
|
||||||
|
//console.log(`${socket.id} can set updates for ${userId}.`);
|
||||||
|
socket.join(userId, function(){
|
||||||
|
//console.log(`${socket.id} joined ${userId}`);
|
||||||
|
});
|
||||||
|
checkForUsers( io, userId );
|
||||||
|
});
|
||||||
|
|
||||||
|
// This socket can receive location (map)
|
||||||
|
socket.on('can-get', function(userId){
|
||||||
|
socket.gets = userId;
|
||||||
|
//console.log(`${socket.id} can get updates for ${userId}.`);
|
||||||
|
socket.join(userId, function(){
|
||||||
|
//console.log(`${socket.id} joined ${userId}`);
|
||||||
|
socket.to(userId).emit('activate', 'true');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set location
|
||||||
|
socket.on('set', function(loc){
|
||||||
|
//console.log(`${socket.id} set location for ${loc.usr}`);
|
||||||
|
loc.time = Date.now();
|
||||||
|
|
||||||
|
// Check for sk32 token
|
||||||
|
if (!loc.tok) { console.log('!loc.tok for loc:',loc) }
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Get loc.usr
|
||||||
|
User.findById(loc.usr, function(err, user) {
|
||||||
|
if (err) { console.log('Error finding user:',err); }
|
||||||
|
if (!user) { console.log('User not found for loc:',loc); }
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Confirm sk32 token
|
||||||
|
if (loc.tok!=user.sk32) { console.log('loc.tok!=user.sk32 || ',loc.tok,'!=',user.sk32); }
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Broadcast location
|
||||||
|
io.to(loc.usr).emit('get', loc);
|
||||||
|
//console.log(`Broadcasting ${loc.lat}, ${loc.lon} to ${loc.usr}`);
|
||||||
|
// Save in db as last seen
|
||||||
|
user.last = {
|
||||||
|
lat: parseFloat(loc.lat),
|
||||||
|
lon: parseFloat(loc.lon),
|
||||||
|
dir: parseFloat(loc.dir||0),
|
||||||
|
spd: parseFloat(loc.spd||0),
|
||||||
|
time: loc.time
|
||||||
|
};
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { console.log('Error saving user last location:'+loc.user+'\n'+err); }
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Shutdown (check for remaining clients)
|
||||||
|
socket.on('disconnect', function(reason){
|
||||||
|
//console.log(`${socket.id} disconnected because of a ${reason}.`);
|
||||||
|
|
||||||
|
// Check if client was receiving updates
|
||||||
|
if (socket.gets){
|
||||||
|
//console.log(`${socket.id} left ${socket.gets}`);
|
||||||
|
checkForUsers( io, socket.gets );
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log errors
|
||||||
|
socket.on('error', function(err){
|
||||||
|
console.log('Socket error! ',err);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "Tracman",
|
||||||
|
"short_name": "Tracman",
|
||||||
|
"author": "Keith Irwin",
|
||||||
|
"description": "GPS tracking service",
|
||||||
|
"homepage_url": "https://github.com/Tracman-org/Server",
|
||||||
|
|
||||||
|
"theme_color": "#222222",
|
||||||
|
"background_color": "#080808",
|
||||||
|
"display": "standalone",
|
||||||
|
"icons": [{
|
||||||
|
"src": "static/img/icon/by/228.png",
|
||||||
|
"sizes": "228x228",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/152.png",
|
||||||
|
"sizes": "152x152",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/128.png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/57.png",
|
||||||
|
"sizes": "57x57",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/48.png",
|
||||||
|
"sizes": "48x48",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/32.png",
|
||||||
|
"sizes": "32x32",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/16.png",
|
||||||
|
"sizes": "16x16",
|
||||||
|
"type": "image/png"
|
||||||
|
}, {
|
||||||
|
"src": "static/img/icon/by/16-32-48.ico",
|
||||||
|
"sizes": "16x16 32x32 48x48",
|
||||||
|
"type": "image/ico"
|
||||||
|
}]
|
||||||
|
}
|
15
package.json
15
package.json
|
@ -1,18 +1,18 @@
|
||||||
{
|
{
|
||||||
"name": "tracman",
|
"name": "tracman",
|
||||||
"version": "0.4.3",
|
"version": "0.5.0",
|
||||||
"description": "Tracks user's GPS location",
|
"description": "Tracks user's GPS location",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.15.0",
|
"body-parser": "^1.17.1",
|
||||||
"connect-flash": "^0.1.1",
|
"connect-flash": "^0.1.1",
|
||||||
"cookie-parser": "^1.4.1",
|
"cookie-parser": "^1.4.1",
|
||||||
"cookie-session": "^2.0.0-alpha.1",
|
"cookie-session": "^2.0.0-alpha.1",
|
||||||
"express": "^4.13.3",
|
"express": "^4.15.2",
|
||||||
"kerberos": "0.0.17",
|
"kerberos": "0.0.17",
|
||||||
"moment": "^2.12.0",
|
"moment": "^2.12.0",
|
||||||
"mongodb": "^2.1.4",
|
"mongodb": "^2.1.4",
|
||||||
"mongoose": "^4.3.5",
|
"mongoose": "^4.9.0",
|
||||||
"node-jose": "^0.8.0",
|
"node-jose": "^0.8.0",
|
||||||
"nunjucks": "^2.3.0",
|
"nunjucks": "^2.3.0",
|
||||||
"passport": "^0.3.2",
|
"passport": "^0.3.2",
|
||||||
|
@ -37,12 +37,7 @@
|
||||||
"test": "mocha test.js",
|
"test": "mocha test.js",
|
||||||
"start": "node server.js",
|
"start": "node server.js",
|
||||||
"dev": "nodemon server.js",
|
"dev": "nodemon server.js",
|
||||||
"deploy": "ssh -t khp 'rsync -aP --delete --exclude-from /srv/tracman/.gitignore --exclude .git kptow:/srv/c9/tracman/ /srv/tracman && sudo systemctl reload-or-restart tracman'",
|
"update": "sudo n stable && sudo npm update --save && sudo npm prune"
|
||||||
"drydeploy": "rsync --dry-run -vaP --delete --exclude-from /srv/c9/tracman/.gitignore --exclude .git /srv/c9/tracman/ khp:/srv/tracman",
|
|
||||||
"revert": "ssh -t khp 'rsync -aP --delete --exclude-from /srv/tracman/.gitignore --exclude .git /srv/tracman/ kptow:/srv/c9/tracman && sudo systemctl reload-or-restart tracman'",
|
|
||||||
"dryrevert": "rsync --dry-run -vaP --delete --exclude-from /srv/c9/tracman/.gitignore --exclude .git khp:/srv/tracman/ /srv/c9/tracman",
|
|
||||||
"log": "ssh -t khp 'journalctl -u tracman'",
|
|
||||||
"restart": "ssh -t khp 'sudo systemctl reload-or-restart tracman'"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
/* IMPORTS */ { var
|
'use strict';
|
||||||
|
|
||||||
|
/* IMPORTS */
|
||||||
|
const
|
||||||
express = require('express'),
|
express = require('express'),
|
||||||
bodyParser = require('body-parser'),
|
bodyParser = require('body-parser'),
|
||||||
cookieParser = require('cookie-parser'),
|
cookieParser = require('cookie-parser'),
|
||||||
|
@ -11,8 +14,9 @@
|
||||||
User = require('./config/models/user.js'),
|
User = require('./config/models/user.js'),
|
||||||
app = express(),
|
app = express(),
|
||||||
http = require('http').Server(app),
|
http = require('http').Server(app),
|
||||||
io = require('socket.io')(http);
|
io = require('socket.io')(http),
|
||||||
}
|
sockets = require('./config/sockets.js');
|
||||||
|
|
||||||
|
|
||||||
/* SETUP */ {
|
/* SETUP */ {
|
||||||
/* Database */ mongoose.connect(secret.mongoSetup, {
|
/* Database */ mongoose.connect(secret.mongoSetup, {
|
||||||
|
@ -59,6 +63,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Routes */ {
|
/* Routes */ {
|
||||||
|
app.get('/favicon.ico', function(req,res){
|
||||||
|
res.redirect('/static/img/icon/by/16-32-48.ico');
|
||||||
|
});
|
||||||
app.use('/',
|
app.use('/',
|
||||||
require('./config/routes/index.js'),
|
require('./config/routes/index.js'),
|
||||||
require('./config/routes/auth.js'),
|
require('./config/routes/auth.js'),
|
||||||
|
@ -103,91 +110,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sockets */ {
|
||||||
|
sockets.init(io);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RUNTIME */ {
|
/* RUNTIME */ {
|
||||||
|
|
||||||
// Check for tracking users
|
|
||||||
function checkForUsers(room) {
|
|
||||||
if (room) {
|
|
||||||
io.to('app-'+room).emit('activate',
|
|
||||||
(io.of("/").adapter.rooms[room])?'true':'false'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
User.find({}, function(err, users){
|
|
||||||
if (err) { console.log('Sockets error finding all users in all rooms: '+err); }
|
|
||||||
users.forEach( function(user){
|
|
||||||
checkForUsers(user.id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Websockets
|
|
||||||
io.on('connection', function(sock) {
|
|
||||||
|
|
||||||
// Set room to map user ID
|
|
||||||
sock.on('room', function(room) {
|
|
||||||
sock.join(room);
|
|
||||||
if (room.slice(0,4)!='app-'){
|
|
||||||
// External user
|
|
||||||
User.findById({_id:room}, function(err, user) {
|
|
||||||
if (err) { console.log('Sockets error finding tracked user of room '+room+'\n'+err); }
|
|
||||||
if (user) {
|
|
||||||
io.to('app-'+room).emit('activate','true'); }
|
|
||||||
});
|
|
||||||
} else { // Sets location
|
|
||||||
checkForUsers(room.slice(4));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Recieving beacon
|
|
||||||
sock.on('app', function(loc){
|
|
||||||
loc.time = Date.now();
|
|
||||||
|
|
||||||
// Check for sk32 token
|
|
||||||
if (loc.tok) {
|
|
||||||
// Get loc.usr
|
|
||||||
User.findById(loc.usr, function(err, user) {
|
|
||||||
if (err) { console.log('Error finding user:',err); }
|
|
||||||
if (!user) { console.log('User not found'); }
|
|
||||||
else {
|
|
||||||
// Confirm sk32 token
|
|
||||||
if (loc.tok!=user.sk32) { console.log('loc.tok!=user.sk32 || ',loc.tok,'!=',user.sk32); }
|
|
||||||
else {
|
|
||||||
// Broadcast location to spectators
|
|
||||||
io.to(loc.usr).emit('trac', loc);
|
|
||||||
// Echo broadcast to transmittors
|
|
||||||
io.to('app-'+loc.usr).emit('trac', loc);
|
|
||||||
// Save in db as last seen
|
|
||||||
user.last = {
|
|
||||||
lat: parseFloat(loc.lat),
|
|
||||||
lon: parseFloat(loc.lon),
|
|
||||||
dir: parseFloat(loc.dir||0),
|
|
||||||
spd: parseFloat(loc.spd||0),
|
|
||||||
time: loc.time
|
|
||||||
};
|
|
||||||
user.save(function(err) {
|
|
||||||
if (err) { console.log('Error saving user last location:'+loc.user+'\n'+err); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Shutdown (check for users)
|
|
||||||
sock.onclose = function(reason){
|
|
||||||
var closedroom = Object.keys(
|
|
||||||
sock.adapter.sids[sock.id]).slice(1)[0];
|
|
||||||
setTimeout(function() {
|
|
||||||
checkForUsers(closedroom);
|
|
||||||
}, 3000);
|
|
||||||
Object.getPrototypeOf(this).onclose.call(this,reason);
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen
|
// Listen
|
||||||
http.listen(secret.port, function(){
|
http.listen(secret.port, function(){
|
||||||
console.log(
|
console.log(
|
||||||
|
@ -195,7 +125,15 @@
|
||||||
'Listening at '+secret.url+
|
'Listening at '+secret.url+
|
||||||
'\n=========================================='
|
'\n=========================================='
|
||||||
);
|
);
|
||||||
checkForUsers();
|
|
||||||
|
// Check for clients for each user
|
||||||
|
User.find({}, function(err, users){
|
||||||
|
if (err) { console.log(`DB error finding all users: ${err.message}`); }
|
||||||
|
users.forEach( function(user){
|
||||||
|
sockets.checkForUsers( io, user.id );
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Alerts */
|
||||||
.centered.alert {
|
.centered.alert {
|
||||||
text-align:center;
|
text-align:center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -17,16 +18,13 @@ body {
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map and streetview */
|
||||||
#map, #pano {position:relative;}
|
#map, #pano {position:relative;}
|
||||||
#pano {float:right;}
|
#pano {float:right;}
|
||||||
.loading {
|
img#panoImg { width:100%; height:100%; }
|
||||||
font-size:7em;
|
#notset {display:none}
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
margin: -56px 0 0 -56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Tracman logo */
|
||||||
.map-logo {
|
.map-logo {
|
||||||
margin-left: -75px;
|
margin-left: -75px;
|
||||||
background: rgba(0,0,0,.7);
|
background: rgba(0,0,0,.7);
|
||||||
|
@ -35,6 +33,7 @@ body {
|
||||||
}
|
}
|
||||||
.map-logo a { color: #fbc93d; }
|
.map-logo a { color: #fbc93d; }
|
||||||
|
|
||||||
|
/* Timestamp */
|
||||||
.tim {
|
.tim {
|
||||||
color: #000;
|
color: #000;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -43,6 +42,9 @@ body {
|
||||||
background-color: rgba(255,255,255,.7);
|
background-color: rgba(255,255,255,.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*TODO: Make signs smaller on mobile */
|
||||||
|
|
||||||
|
/* Speed sign */
|
||||||
.spd {
|
.spd {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
height: 40px;}
|
height: 40px;}
|
||||||
|
@ -55,6 +57,7 @@ body {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
}
|
}
|
||||||
|
/* Altitude sign */
|
||||||
.alt-unit, .spd-unit { font-size:12px; }
|
.alt-unit, .spd-unit { font-size:12px; }
|
||||||
.alt-label, .spd-label {
|
.alt-label, .spd-label {
|
||||||
font-size:18px;
|
font-size:18px;
|
||||||
|
@ -71,3 +74,11 @@ body {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
background-color: #009800;
|
background-color: #009800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Control buttons */
|
||||||
|
.btn {
|
||||||
|
z-index: 50;
|
||||||
|
background: #222;
|
||||||
|
} .btn:hover {
|
||||||
|
background: #333;
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
||||||
|
|
||||||
},{}]},{},[1]);
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
|
||||||
// Open drawer with hamburger
|
// Open drawer with hamburger
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
jQuery.extend(jQuery.easing,{
|
jQuery.extend(jQuery.easing,{
|
||||||
easeInOutExpo: function(x, t, b, c, d){
|
easeInOutExpo: function(x, t, b, c, d){
|
||||||
if (t==0) return b;
|
if (t==0) return b;
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*! jQuery UI - v1.11.4 - 2016-06-30
|
|
||||||
* http://jqueryui.com
|
|
||||||
* Includes: core.css, tabs.css
|
|
||||||
* Copyright jQuery Foundation and other contributors; Licensed MIT */
|
|
||||||
|
|
||||||
/* Layout helpers
|
|
||||||
----------------------------------*/
|
|
||||||
.ui-helper-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.ui-helper-hidden-accessible {
|
|
||||||
border: 0;
|
|
||||||
clip: rect(0 0 0 0);
|
|
||||||
height: 1px;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
.ui-helper-reset {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
line-height: 1.3;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 100%;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.ui-helper-clearfix:before,
|
|
||||||
.ui-helper-clearfix:after {
|
|
||||||
content: "";
|
|
||||||
display: table;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
.ui-helper-clearfix:after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.ui-helper-clearfix {
|
|
||||||
min-height: 0; /* support: IE7 */
|
|
||||||
}
|
|
||||||
.ui-helper-zfix {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
filter:Alpha(Opacity=0); /* support: IE8 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui-front {
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Interaction Cues
|
|
||||||
----------------------------------*/
|
|
||||||
.ui-state-disabled {
|
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Icons
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* states and images */
|
|
||||||
.ui-icon {
|
|
||||||
display: block;
|
|
||||||
text-indent: -99999px;
|
|
||||||
overflow: hidden;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Misc visuals
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* Overlays */
|
|
||||||
.ui-widget-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.ui-tabs {
|
|
||||||
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
|
||||||
padding: .2em;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav {
|
|
||||||
margin: 0;
|
|
||||||
padding: .2em .2em 0;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav li {
|
|
||||||
list-style: none;
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
margin: 1px .2em 0 0;
|
|
||||||
border-bottom-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
|
|
||||||
float: left;
|
|
||||||
padding: .5em 1em;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
padding-bottom: 1px;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-panel {
|
|
||||||
display: block;
|
|
||||||
border-width: 0;
|
|
||||||
padding: 1em 1.4em;
|
|
||||||
background: none;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +0,0 @@
|
||||||
/*! jQuery UI - v1.11.4 - 2016-06-30
|
|
||||||
* http://jqueryui.com
|
|
||||||
* Includes: core.css, tabs.css
|
|
||||||
* Copyright jQuery Foundation and other contributors; Licensed MIT */
|
|
||||||
|
|
||||||
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,134 +0,0 @@
|
||||||
/*!
|
|
||||||
* jQuery UI CSS Framework 1.11.4
|
|
||||||
* http://jqueryui.com
|
|
||||||
*
|
|
||||||
* Copyright jQuery Foundation and other contributors
|
|
||||||
* Released under the MIT license.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://api.jqueryui.com/category/theming/
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Layout helpers
|
|
||||||
----------------------------------*/
|
|
||||||
.ui-helper-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.ui-helper-hidden-accessible {
|
|
||||||
border: 0;
|
|
||||||
clip: rect(0 0 0 0);
|
|
||||||
height: 1px;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
.ui-helper-reset {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
line-height: 1.3;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 100%;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.ui-helper-clearfix:before,
|
|
||||||
.ui-helper-clearfix:after {
|
|
||||||
content: "";
|
|
||||||
display: table;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
.ui-helper-clearfix:after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.ui-helper-clearfix {
|
|
||||||
min-height: 0; /* support: IE7 */
|
|
||||||
}
|
|
||||||
.ui-helper-zfix {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
filter:Alpha(Opacity=0); /* support: IE8 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui-front {
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Interaction Cues
|
|
||||||
----------------------------------*/
|
|
||||||
.ui-state-disabled {
|
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Icons
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* states and images */
|
|
||||||
.ui-icon {
|
|
||||||
display: block;
|
|
||||||
text-indent: -99999px;
|
|
||||||
overflow: hidden;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Misc visuals
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* Overlays */
|
|
||||||
.ui-widget-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.ui-tabs {
|
|
||||||
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
|
||||||
padding: .2em;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav {
|
|
||||||
margin: 0;
|
|
||||||
padding: .2em .2em 0;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav li {
|
|
||||||
list-style: none;
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
margin: 1px .2em 0 0;
|
|
||||||
border-bottom-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
|
|
||||||
float: left;
|
|
||||||
padding: .5em 1em;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
padding-bottom: 1px;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
|
|
||||||
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.ui-tabs .ui-tabs-panel {
|
|
||||||
display: block;
|
|
||||||
border-width: 0;
|
|
||||||
padding: 1em 1.4em;
|
|
||||||
background: none;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
/*! jQuery UI - v1.11.4 - 2016-06-30
|
|
||||||
* http://jqueryui.com
|
|
||||||
* Copyright jQuery Foundation and other contributors; Licensed MIT */
|
|
||||||
|
|
||||||
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends 'templates/base.html' %}
|
||||||
|
{% block title %}{{super()}} | Help{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<section class='container'>
|
||||||
|
|
||||||
|
<h2>Help</h2>
|
||||||
|
|
||||||
|
<p><i>Welcome to Tracman! Here's how to get started. </i></p>
|
||||||
|
|
||||||
|
<p><u>Set</u> sets your location once using this device's geolocation. On a GPS-enabled phone, the location will be set to its coordinates. </p>
|
||||||
|
|
||||||
|
<p><u>Track</u> sets your location as above, but continues to track your location as long as you keep this window open. On a phone, this can drain the battery fast, so be careful! </p>
|
||||||
|
|
||||||
|
<p><u>Clear</u> clears your location instantly. Anyone looking at your map will see a blank screen instead. Use this to hide your location. </p>
|
||||||
|
|
||||||
|
<p>Share your location by sending the URL to anyone. They won't need an account to view the map. </p>
|
||||||
|
|
||||||
|
<a href="/map" class='btn' style="width:60%; position:relative; left:20%; background:#333">Go to map <i class='fa fa-angle-right'></i></a>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
324
views/map.html
324
views/map.html
|
@ -5,48 +5,7 @@
|
||||||
{{super()}}
|
{{super()}}
|
||||||
<link href="/static/css/map.css" rel="stylesheet">
|
<link href="/static/css/map.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
#notset {display:none}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
z-index: 50;
|
|
||||||
background: #222;
|
|
||||||
} .btn:hover {
|
|
||||||
background: #333;
|
|
||||||
}
|
|
||||||
.popup {
|
|
||||||
padding: 5vw;
|
|
||||||
border-radius: 5vw;
|
|
||||||
z-index: 100;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
background: #222;
|
|
||||||
-moz-box-shadow: 3px 4px 6px #000;
|
|
||||||
-webkit-box-shadow: 3px 4px 6px #000;
|
|
||||||
box-shadow: 3px 4px 6px #000;
|
|
||||||
top: calc(60px + 5vw);
|
|
||||||
bottom: calc(30px + 5vw);
|
|
||||||
left:5vw; right: 5vw;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}.popup .close {
|
|
||||||
position: relative;
|
|
||||||
top: -15px;
|
|
||||||
left: 10px;
|
|
||||||
float: right;
|
|
||||||
}.popup pre {
|
|
||||||
background: rgba(0,0,0,.5);
|
|
||||||
border: 1px solid #FFF;
|
|
||||||
padding: 1vw;
|
|
||||||
}.popup .btn {
|
|
||||||
background: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*TODO: Smaller signs on mobile*/
|
|
||||||
/*.spd-sign {}*/
|
|
||||||
/*.alt-sign {}*/
|
|
||||||
|
|
||||||
.wrap { top:{% if not noHeader %}58{% else %}0{% endif %}px;}
|
.wrap { top:{% if not noHeader %}58{% else %}0{% endif %}px;}
|
||||||
img#panoImg { width:100%; height:100%; }
|
|
||||||
|
|
||||||
{% if mapuser.settings.showStreetview and disp!='0' and disp!='1' %}
|
{% if mapuser.settings.showStreetview and disp!='0' and disp!='1' %}
|
||||||
/* show both */
|
/* show both */
|
||||||
|
@ -83,201 +42,6 @@
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
{% if user %}
|
|
||||||
|
|
||||||
<div class='share popup'>
|
|
||||||
<style>
|
|
||||||
.share .fa {
|
|
||||||
text-align: center;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding-top: 7px;
|
|
||||||
background: rgba(255,255,255,.2);
|
|
||||||
-moz-box-shadow: 2px 2px 4px #000;
|
|
||||||
-webkit-box-shadow: 2px 2px 4px #000;
|
|
||||||
box-shadow: 2px 2px 4px #000;
|
|
||||||
}.share .fa:hover {
|
|
||||||
background: rgba(255,255,255,.4);
|
|
||||||
}.share .fa:active {
|
|
||||||
-moz-box-shadow: 0;
|
|
||||||
-webkit-box-shadow: 0;
|
|
||||||
box-shadow: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class='close'>
|
|
||||||
<a href="#" title="close"><i class='fa fa-times'></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Share</h2>
|
|
||||||
|
|
||||||
<p>This link will display the map of your location:
|
|
||||||
<a href="/map/{{user.slug}}">https://tracman.org/map/{{user.slug}}</a>
|
|
||||||
<br>Here are some buttons for your convienence:
|
|
||||||
<a href="https://twitter.com/home?status=A%20map%20of%20my%20realtime%20location:%20https://tracman.org/map/{{user.slug}}" target="_blank"><i class="fa fa-twitter"></i></a>
|
|
||||||
<a href="https://www.facebook.com/sharer/sharer.php?u=https://tracman.org/map/{{user.slug}}" target="_blank"><i class="share fa fa-facebook"></i></a>
|
|
||||||
<a href="https://www.reddit.com/submit?title=A%20map%20of%20my%20realtime%20location&url=https://tracman.org/map/{{user.slug}}" target="_blank"><i class="fa fa-reddit-alien"></i></a>
|
|
||||||
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https://tracman.org/map/{{user.slug}}&title=A%20map%20of%20my%20realtime%20location" target="_blank"><i class="share fa fa-linkedin"></i></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>You can also embed a map into your website with this code. Be sure to set the width and height attributes to suit your circumstance.
|
|
||||||
<pre><iframe src="https://tracman.org/map/{{user.slug}}?noheader=1" width="90%" style="height:90vh"></iframe></pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<a href="#" class='btn' style="width:100%">OK</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='settings popup'>
|
|
||||||
<div class='close'>
|
|
||||||
<a href="#" title="close"><i class='fa fa-times'></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Settings</h2>
|
|
||||||
|
|
||||||
<script src="/static/js/validator.min.js"></script>
|
|
||||||
<form id='settings-form' class='col-lg-10 col-lg-offset-1 form-horizontal' data-toggle="validator" role="form" method="post">
|
|
||||||
|
|
||||||
<div id='name' class='form-group' title="This appears in your page's title. ">
|
|
||||||
<label class='control-label col-sm-2 col-lg-3' for="name">Name</label>
|
|
||||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
|
||||||
<input class='form-control' name="name" type="text" value="{{user.name}}"
|
|
||||||
maxlength="160" data-error="Invalid input"><br>
|
|
||||||
</div>
|
|
||||||
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='email' class='form-group' title="For account stuff, no dumb newsletters. ">
|
|
||||||
<label class='control-label col-sm-2 col-lg-3' for="email">Email</label>
|
|
||||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
|
||||||
<input class='form-control' name="email" type="email" value="{{user.email}}"
|
|
||||||
maxlength="160" data-error="Invalid input"><br>
|
|
||||||
</div>
|
|
||||||
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='slug' class='form-group' title="This is the URL which shows your location. Be careful whom you share it with! ">
|
|
||||||
<label class='control-label col-sm-2 col-lg-3' for="slug">URL</label>
|
|
||||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
|
||||||
<span class='input-group-addon'>tracman.org/map/</span>
|
|
||||||
<input class='form-control' type="text" name="slug" value="{{user.slug}}" required data-remote="/validate"
|
|
||||||
maxlength="160" data-remote-error="That URL is already taken. " data-error="Invalid input"><br>
|
|
||||||
</div>
|
|
||||||
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='units' class='form-group col-xs-12' title="Select standard units for feet and miles/hour. Select metric units if you are a commie. ">
|
|
||||||
<label class='control-label col-sm-4 col-lg-3' for="units">Units</label>
|
|
||||||
<div class='input-group col-sm-8 col-lg-9'>
|
|
||||||
<div class='radio-inline'><label>
|
|
||||||
<input type="radio" name="units" value="standard" {% if user.settings.units == 'standard' %}checked{% endif %}>
|
|
||||||
Standard
|
|
||||||
</label></div>
|
|
||||||
<div class='radio-inline'><label>
|
|
||||||
<input type="radio" name="units" value="metric" {% if user.settings.units == 'metric' %}checked{% endif %}>
|
|
||||||
Metric
|
|
||||||
</label></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='defaultMap' class='form-group col-xs-12' title="Shows whether to show a satellite image or standard google road map as the default on your page. Visitors will have the option to change this. Note that satellite images load slower. ">
|
|
||||||
<label class='control-label col-sm-4 col-lg-3' for="map">Default map</label>
|
|
||||||
<div class='input-group col-sm-8 col-lg-9'>
|
|
||||||
<div class='radio-inline'><label>
|
|
||||||
<input type="radio" name="map" value="road" {% if user.settings.defaultMap == 'road' %}checked{% endif %}>
|
|
||||||
Road
|
|
||||||
</label></div>
|
|
||||||
<div class='radio-inline'><label>
|
|
||||||
<input type="radio" name="map" value="sat" {% if user.settings.defaultMap == 'sat' %}checked{% endif %}>
|
|
||||||
Satellite
|
|
||||||
</label></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='defaultZoom' class='form-group col-xs-12' title="Shows the initial map zoom level on your page. A higher number means more zoom. Note that the size of the viewing window will also have an effect on how much of the map a visitor can see. ">
|
|
||||||
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="map">Default zoom</label>
|
|
||||||
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
|
||||||
<select class='c-select' name="zoom">
|
|
||||||
<option {% if user.settings.defaultZoom==1 %}selected {% endif %}value="1">1 World</option>
|
|
||||||
<option {% if user.settings.defaultZoom==2 %}selected {% endif %}value="2">2</option>
|
|
||||||
<option {% if user.settings.defaultZoom==3 %}selected {% endif %}value="3">3</option>
|
|
||||||
<option {% if user.settings.defaultZoom==4 %}selected {% endif %}value="4">4</option>
|
|
||||||
<option {% if user.settings.defaultZoom==5 %}selected {% endif %}value="5">5 Landmass</option>
|
|
||||||
<option {% if user.settings.defaultZoom==6 %}selected {% endif %}value="6">6</option>
|
|
||||||
<option {% if user.settings.defaultZoom==7 %}selected {% endif %}value="7">7</option>
|
|
||||||
<option {% if user.settings.defaultZoom==8 %}selected {% endif %}value="8">8</option>
|
|
||||||
<option {% if user.settings.defaultZoom==9 %}selected {% endif %}value="9">9</option>
|
|
||||||
<option {% if user.settings.defaultZoom==10 %}selected {% endif %}value="10">10 City</option>
|
|
||||||
<option {% if user.settings.defaultZoom==11 %}selected {% endif %}value="11">11</option>
|
|
||||||
<option {% if user.settings.defaultZoom==12 %}selected {% endif %}value="12">12</option>
|
|
||||||
<option {% if user.settings.defaultZoom==13 %}selected {% endif %}value="13">13</option>
|
|
||||||
<option {% if user.settings.defaultZoom==14 %}selected {% endif %}value="14">14</option>
|
|
||||||
<option {% if user.settings.defaultZoom==15 %}selected {% endif %}value="15">15 Streets</option>
|
|
||||||
<option {% if user.settings.defaultZoom==16 %}selected {% endif %}value="16">16</option>
|
|
||||||
<option {% if user.settings.defaultZoom==17 %}selected {% endif %}value="17">17</option>
|
|
||||||
<option {% if user.settings.defaultZoom==18 %}selected {% endif %}value="18">18</option>
|
|
||||||
<option {% if user.settings.defaultZoom==19 %}selected {% endif %}value="19">19</option>
|
|
||||||
<option {% if user.settings.defaultZoom==20 %}selected {% endif %}value="20">20 Buildings</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='showSpeed' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows a spedometer on the map.">
|
|
||||||
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showSpeed">Show speed{% if not user.isPro %} <span class='red'>(PRO)</span>{% endif %}</label>
|
|
||||||
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
|
||||||
<input class='form-control' name="showSpeed" type="checkbox" {% if not user.isPro %}disabled {% elif user.settings.showSpeed %}checked{% else %}{% endif %}><br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='showAltitude' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows the current elevation on the map. ">
|
|
||||||
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showAlt">Show altitude{% if not user.isPro %} <span class='red'>(PRO)</span>{% endif %}</label>
|
|
||||||
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
|
||||||
<input class='form-control' name="showAlt" type="checkbox" {% if not user.isPro %}disabled {% elif user.settings.showAlt %}checked{% else %}{% endif %}><br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='showStreet' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows a Google street view image at or near your current location, oriented in the direction of travel. ">
|
|
||||||
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showStreet">Show street view{% if not user.isPro %} <span class='red'>(PRO)</span><br>{% endif %}</label>
|
|
||||||
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
|
||||||
<input class='form-control' name="showStreet" type="checkbox" {% if not user.isPro %}disabled{% elif user.settings.showStreetview %}checked{% else %}{% endif %}><br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='delete' class='form-group col-xs-12'>
|
|
||||||
<a class='btn red col-xs-5 col-md-3' style='margin-bottom:5px;float:right;' onclick="deleteAccount()">Delete account</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='submit' class='form-group col-xs-12 flexbox' style="padding:0 0 60px">
|
|
||||||
<input class='btn yellow' style="width:50%;" type="submit" value="Save">
|
|
||||||
<a href="#" class='btn' style="width:50%">cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% if not user.isPro %}<p style="clear:both">Want to try <a href="/pro">Tracman Pro</a>? It's free during beta testing. </p>{% endif %}
|
|
||||||
<p style="clear:both">Would you like to submit a <a href="https://productpains.com/create/tracman">suggestion</a> or <a href="https://github.com/Tracman-org/Server/issues/new">bug report</a>? </p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='help popup'>
|
|
||||||
<div class='close'>
|
|
||||||
<a href="#" title="close"><i class='fa fa-times'></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Help</h2>
|
|
||||||
|
|
||||||
{% if newuser %}<p><i>Welcome to Tracman! Here's how to get started. </i></p>{% endif %}
|
|
||||||
|
|
||||||
<p><u>Set</u> sets your location once using this device's geolocation. On a GPS-enabled phone, the location will be set to its coordinates. </p>
|
|
||||||
|
|
||||||
<p><u>Track</u> sets your location as above, but continues to track your location as long as you keep this window open. On a phone, this can drain the battery fast, so be careful! </p>
|
|
||||||
|
|
||||||
<p><u>Clear</u> clears your location instantly. Anyone looking at your map will see a blank screen instead. Use this to hide your location. </p>
|
|
||||||
|
|
||||||
{% if newuser %}<p>Share your location by sending the URL to anyone. They won't need an account to view the map. </p>{% endif %}
|
|
||||||
|
|
||||||
<a href="#" class='btn' style="width:100%">OK</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class='wrap'>
|
<div class='wrap'>
|
||||||
|
|
||||||
<div id='map'></div>
|
<div id='map'></div>
|
||||||
|
@ -321,14 +85,13 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js" integrity="sha256-WKvqiY0jZHWQZIohYEmr9KUC5rEaYEOFTq+ByllJK8w=" crossorigin="anonymous"></script>
|
||||||
<script src="/static/js/bundle.js"></script>
|
<script src="https://maps.googleapis.com/maps/api/js?key={{mapApi}}&callback=gmapsCb" async defer></script>
|
||||||
<script src="https://maps.googleapis.com/maps/api/js?key={{api}}&callback=gmapsCb" async defer></script>
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
/* Variables */ {
|
/* Variables */ {
|
||||||
var wpid, map, pano, sv, marker, elevator,
|
var wpid, map, pano, sv, marker, elevator,
|
||||||
sock = io.connect(),
|
socket = io('//'+window.location.hostname),
|
||||||
mapuserid = {{mapuser._id |dump|safe}},
|
mapuserid = {{mapuser._id |dump|safe}},
|
||||||
userid{% if user._id %} = {{user._id |dump|safe}}{% endif %},
|
userid{% if user._id %} = {{user._id |dump|safe}}{% endif %},
|
||||||
settings = JSON.parse('{{mapuser.settings |dump|safe}}'),
|
settings = JSON.parse('{{mapuser.settings |dump|safe}}'),
|
||||||
|
@ -339,24 +102,31 @@
|
||||||
panoElem = document.getElementById('pano');
|
panoElem = document.getElementById('pano');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to socket.io
|
function onConnect(socket,userid,mapuserid){
|
||||||
sock.on('connect', function(){
|
|
||||||
sock.emit('room',
|
|
||||||
(userid)? 'app-'+userid :mapuserid
|
|
||||||
);
|
|
||||||
// }).on('data', function (data) {
|
|
||||||
// console.log(data);
|
|
||||||
}).on('error', function (err){
|
|
||||||
console.error('Unable to connect Socket.IO', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check for location.hash capability (IE9+)
|
// Can get location
|
||||||
if (!'onhashchange' in window) {
|
socket.emit('can-get', mapuserid );
|
||||||
if (!confirm("location.hash won't work in IE<9. If you don't know how to fix this, click cancel. ")){
|
//console.log(`Receiving updates for ${mapuserid}.`);
|
||||||
window.open("https://whatbrowser.org/");
|
|
||||||
|
// Can set location too
|
||||||
|
if (mapuserid==userid){
|
||||||
|
socket.emit('can-set', userid );
|
||||||
|
//console.log(`Sending updates for ${userid}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connect to socket.io
|
||||||
|
socket.on('connect', function(){
|
||||||
|
//console.log(`Connected... `);
|
||||||
|
onConnect(socket,userid,mapuserid);
|
||||||
|
}).on('reconnect', function(){
|
||||||
|
//console.log(`Reconnected... `);
|
||||||
|
onConnect(socket,userid,mapuserid);
|
||||||
|
}).on('error', function (err){
|
||||||
|
console.error(`Unable to connect because of: ${err.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
// Parse location
|
// Parse location
|
||||||
function parseLoc(loc) {
|
function parseLoc(loc) {
|
||||||
loc.spd = (settings.units=='standard')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd)
|
loc.spd = (settings.units=='standard')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd)
|
||||||
|
@ -474,30 +244,10 @@
|
||||||
updateStreetView(parseLoc(last),10);
|
updateStreetView(parseLoc(last),10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open popups
|
|
||||||
function setPopups() {
|
|
||||||
if (location.hash === "#share") {
|
|
||||||
$('.settings.popup').hide();
|
|
||||||
$('.share.popup').show();
|
|
||||||
$('.help.popup').hide();
|
|
||||||
} else if (location.hash === "#settings") {
|
|
||||||
$('.settings.popup').show();
|
|
||||||
$('.share.popup').hide();
|
|
||||||
$('.help.popup').hide();
|
|
||||||
} else if (location.hash === "#help") {
|
|
||||||
$('.settings.popup').hide();
|
|
||||||
$('.share.popup').hide();
|
|
||||||
$('.help.popup').show();
|
|
||||||
} else {
|
|
||||||
$('.settings.popup').hide();
|
|
||||||
$('.share.popup').hide();
|
|
||||||
$('.help.popup').hide();
|
|
||||||
}
|
|
||||||
} setPopups(); // Execute immediately
|
|
||||||
window.onhashchange = setPopups; // Execute on change
|
|
||||||
|
|
||||||
// Get location
|
// Get location
|
||||||
sock.on('trac', function(loc) {
|
socket.on('get', function(loc) {
|
||||||
|
//console.log(`Received location: ${loc.lat}, ${loc.lon}`);
|
||||||
|
|
||||||
loc = parseLoc(loc);
|
loc = parseLoc(loc);
|
||||||
if (disp!='1' || !settings.showStreetview) {
|
if (disp!='1' || !settings.showStreetview) {
|
||||||
$('.tim').text('location updated '+loc.time);
|
$('.tim').text('location updated '+loc.time);
|
||||||
|
@ -531,11 +281,16 @@
|
||||||
lon: pos.coords.longitude,
|
lon: pos.coords.longitude,
|
||||||
spd: (pos.coords.speed||0)
|
spd: (pos.coords.speed||0)
|
||||||
}
|
}
|
||||||
sock.emit('app',newloc);
|
socket.broadcast.emit('app', newloc);
|
||||||
toggleMaps(newloc);
|
toggleMaps(newloc);
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
console.log('done getting position');
|
if (err) {
|
||||||
if (err) { console.log('ERROR: '+err); }
|
alert("Unable to set location.");
|
||||||
|
io.emit('log',err.message);
|
||||||
|
console.error(err.message); }
|
||||||
|
else {
|
||||||
|
//console.log('Set position',pos);
|
||||||
|
}
|
||||||
}, { enableHighAccuracy:true });
|
}, { enableHighAccuracy:true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -563,10 +318,13 @@
|
||||||
lon: pos.coords.longitude,
|
lon: pos.coords.longitude,
|
||||||
spd: (pos.coords.speed||0)
|
spd: (pos.coords.speed||0)
|
||||||
};
|
};
|
||||||
sock.emit('app',newloc);
|
socket.broadcast.emit('app',newloc);
|
||||||
toggleMaps(newloc);
|
toggleMaps(newloc);
|
||||||
}, function(err){
|
}, function(err){
|
||||||
alert('Failed to track: \n'+err);
|
if (err) {
|
||||||
|
alert("Unable to track location.");
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
}, { enableHighAccuracy:true });
|
}, { enableHighAccuracy:true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,7 +346,7 @@
|
||||||
usr: userid,
|
usr: userid,
|
||||||
lat:0, lon:0, spd:0
|
lat:0, lon:0, spd:0
|
||||||
}
|
}
|
||||||
sock.emit('app',newloc);
|
socket.broadcast.emit('app',newloc);
|
||||||
toggleMaps(newloc);
|
toggleMaps(newloc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
{% extends 'templates/base.html' %}
|
||||||
|
{% block title %}{{super()}} | Settings{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<section class='container'>
|
||||||
|
|
||||||
|
<h2>Settings</h2>
|
||||||
|
|
||||||
|
<script src="/static/js/validator.min.js"></script>
|
||||||
|
<form id='settings-form' class='col-lg-10 col-lg-offset-1 form-horizontal' data-toggle="validator" role="form" method="post">
|
||||||
|
|
||||||
|
<div id='name' class='form-group' title="This appears in your page's title. ">
|
||||||
|
<label class='control-label col-sm-2 col-lg-3' for="name">Name</label>
|
||||||
|
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||||
|
<input class='form-control' name="name" type="text" value="{{user.name}}"
|
||||||
|
maxlength="160" data-error="Invalid input"><br>
|
||||||
|
</div>
|
||||||
|
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='email' class='form-group' title="For account stuff, no dumb newsletters. ">
|
||||||
|
<label class='control-label col-sm-2 col-lg-3' for="email">Email</label>
|
||||||
|
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||||
|
<input class='form-control' name="email" type="email" value="{{user.email}}"
|
||||||
|
maxlength="160" data-error="Invalid input"><br>
|
||||||
|
</div>
|
||||||
|
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='slug' class='form-group' title="This is the URL which shows your location. Be careful whom you share it with! ">
|
||||||
|
<label class='control-label col-sm-2 col-lg-3' for="slug">URL</label>
|
||||||
|
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||||
|
<span class='input-group-addon'>tracman.org/map/</span>
|
||||||
|
<input class='form-control' type="text" name="slug" value="{{user.slug}}" required data-remote="/validate"
|
||||||
|
maxlength="160" data-remote-error="That URL is already taken. " data-error="Invalid input"><br>
|
||||||
|
</div>
|
||||||
|
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='units' class='form-group col-xs-12' title="Select standard units for feet and miles/hour. Select metric units if you are a commie. ">
|
||||||
|
<label class='control-label col-sm-4 col-lg-3' for="units">Units</label>
|
||||||
|
<div class='input-group col-sm-8 col-lg-9'>
|
||||||
|
<div class='radio-inline'><label>
|
||||||
|
<input type="radio" name="units" value="standard" {% if user.settings.units == 'standard' %}checked{% endif %}>
|
||||||
|
Standard
|
||||||
|
</label></div>
|
||||||
|
<div class='radio-inline'><label>
|
||||||
|
<input type="radio" name="units" value="metric" {% if user.settings.units == 'metric' %}checked{% endif %}>
|
||||||
|
Metric
|
||||||
|
</label></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='defaultMap' class='form-group col-xs-12' title="Shows whether to show a satellite image or standard google road map as the default on your page. Visitors will have the option to change this. Note that satellite images load slower. ">
|
||||||
|
<label class='control-label col-sm-4 col-lg-3' for="map">Default map</label>
|
||||||
|
<div class='input-group col-sm-8 col-lg-9'>
|
||||||
|
<div class='radio-inline'><label>
|
||||||
|
<input type="radio" name="map" value="road" {% if user.settings.defaultMap == 'road' %}checked{% endif %}>
|
||||||
|
Road
|
||||||
|
</label></div>
|
||||||
|
<div class='radio-inline'><label>
|
||||||
|
<input type="radio" name="map" value="sat" {% if user.settings.defaultMap == 'sat' %}checked{% endif %}>
|
||||||
|
Satellite
|
||||||
|
</label></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='defaultZoom' class='form-group col-xs-12' title="Shows the initial map zoom level on your page. A higher number means more zoom. Note that the size of the viewing window will also have an effect on how much of the map a visitor can see. ">
|
||||||
|
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="map">Default zoom</label>
|
||||||
|
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
||||||
|
<select class='c-select' name="zoom">
|
||||||
|
<option {% if user.settings.defaultZoom==1 %}selected {% endif %}value="1">1 World</option>
|
||||||
|
<option {% if user.settings.defaultZoom==2 %}selected {% endif %}value="2">2</option>
|
||||||
|
<option {% if user.settings.defaultZoom==3 %}selected {% endif %}value="3">3</option>
|
||||||
|
<option {% if user.settings.defaultZoom==4 %}selected {% endif %}value="4">4</option>
|
||||||
|
<option {% if user.settings.defaultZoom==5 %}selected {% endif %}value="5">5 Landmass</option>
|
||||||
|
<option {% if user.settings.defaultZoom==6 %}selected {% endif %}value="6">6</option>
|
||||||
|
<option {% if user.settings.defaultZoom==7 %}selected {% endif %}value="7">7</option>
|
||||||
|
<option {% if user.settings.defaultZoom==8 %}selected {% endif %}value="8">8</option>
|
||||||
|
<option {% if user.settings.defaultZoom==9 %}selected {% endif %}value="9">9</option>
|
||||||
|
<option {% if user.settings.defaultZoom==10 %}selected {% endif %}value="10">10 City</option>
|
||||||
|
<option {% if user.settings.defaultZoom==11 %}selected {% endif %}value="11">11</option>
|
||||||
|
<option {% if user.settings.defaultZoom==12 %}selected {% endif %}value="12">12</option>
|
||||||
|
<option {% if user.settings.defaultZoom==13 %}selected {% endif %}value="13">13</option>
|
||||||
|
<option {% if user.settings.defaultZoom==14 %}selected {% endif %}value="14">14</option>
|
||||||
|
<option {% if user.settings.defaultZoom==15 %}selected {% endif %}value="15">15 Streets</option>
|
||||||
|
<option {% if user.settings.defaultZoom==16 %}selected {% endif %}value="16">16</option>
|
||||||
|
<option {% if user.settings.defaultZoom==17 %}selected {% endif %}value="17">17</option>
|
||||||
|
<option {% if user.settings.defaultZoom==18 %}selected {% endif %}value="18">18</option>
|
||||||
|
<option {% if user.settings.defaultZoom==19 %}selected {% endif %}value="19">19</option>
|
||||||
|
<option {% if user.settings.defaultZoom==20 %}selected {% endif %}value="20">20 Buildings</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='showSpeed' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows a spedometer on the map.">
|
||||||
|
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showSpeed">Show speed{% if not user.isPro %} <span class='red'>(PRO)</span>{% endif %}</label>
|
||||||
|
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
||||||
|
<input class='form-control' name="showSpeed" type="checkbox" {% if not user.isPro %}disabled {% elif user.settings.showSpeed %}checked{% else %}{% endif %}><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='showAltitude' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows the current elevation on the map. ">
|
||||||
|
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showAlt">Show altitude{% if not user.isPro %} <span class='red'>(PRO)</span>{% endif %}</label>
|
||||||
|
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
||||||
|
<input class='form-control' name="showAlt" type="checkbox" {% if not user.isPro %}disabled {% elif user.settings.showAlt %}checked{% else %}{% endif %}><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='showStreet' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows a Google street view image at or near your current location, oriented in the direction of travel. ">
|
||||||
|
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showStreet">Show street view{% if not user.isPro %} <span class='red'>(PRO)</span><br>{% endif %}</label>
|
||||||
|
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
|
||||||
|
<input class='form-control' name="showStreet" type="checkbox" {% if not user.isPro %}disabled{% elif user.settings.showStreetview %}checked{% else %}{% endif %}><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='delete' class='form-group col-xs-12'>
|
||||||
|
<a class='btn red col-xs-5 col-md-3' style='margin-bottom:5px;float:right;' onclick="deleteAccount()">Delete account</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='submit' class='form-group col-xs-12 flexbox' style="padding:0 0 60px">
|
||||||
|
<input class='btn yellow' style="width:50%; background:#333" type="submit" value="Save">
|
||||||
|
<a href="#" class='btn' style="width:50%; background:#333">cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if not user.isPro %}<p style="clear:both">Want to try <a href="/pro">Tracman Pro</a>? It's free during beta testing. </p>{% endif %}
|
||||||
|
<p style="clear:both">Would you like to <a href="https://github.com/Tracman-org/Server/issues/new">submit a suggestion or bug report</a>? </p>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -49,6 +49,7 @@
|
||||||
{% block main %}Loading... {% endblock %}
|
{% block main %}Loading... {% endblock %}
|
||||||
{% if not noFooter %}{% include 'templates/footer.html' %}{% endif %}
|
{% if not noFooter %}{% include 'templates/footer.html' %}{% endif %}
|
||||||
|
|
||||||
|
<!-- Google Analytics -->
|
||||||
<script>
|
<script>
|
||||||
(function(t,r,a,c,m,o,n){t['GoogleAnalyticsObject']=m;t[m]=t[m]||function(){
|
(function(t,r,a,c,m,o,n){t['GoogleAnalyticsObject']=m;t[m]=t[m]||function(){
|
||||||
(t[m].q=t[m].q||[]).push(arguments);},t[m].l=1*new Date();o=r.createElement(a),
|
(t[m].q=t[m].q||[]).push(arguments);},t[m].l=1*new Date();o=r.createElement(a),
|
||||||
|
@ -60,5 +61,17 @@
|
||||||
ga('send','pageview');
|
ga('send','pageview');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Firebase -->
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/3.7.0/firebase.js"></script>
|
||||||
|
<script>
|
||||||
|
firebase.initializeApp({
|
||||||
|
apiKey: "AIzaSyDPYY_Fw3FXLm0hKfIfc8qlrc98zZiN4IY",
|
||||||
|
authDomain: "tracman-b894f.firebaseapp.com",
|
||||||
|
databaseURL: "https://tracman-b894f.firebaseio.com",
|
||||||
|
storageBucket: "tracman-b894f.appspot.com",
|
||||||
|
messagingSenderId: "483494341936"
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
<ul>
|
<ul>
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<li><a href="/map/{{user.slug}}">Map</a></li>
|
<li><a href="/map/{{user.slug}}">Map</a></li>
|
||||||
<li><a href="/map#share">Share</a></li>
|
<li><a href="/settings">Settings</a></li>
|
||||||
<li><a href="/map#settings">Settings</a></li>
|
|
||||||
{% if user.isAdmin %}<li><a href="/admin">Admin</a></li>{% endif %}
|
{% if user.isAdmin %}<li><a href="/admin">Admin</a></li>{% endif %}
|
||||||
<li><a href="/map#help">Help</a></li>
|
<li><a href="/help">Help</a></li>
|
||||||
<li><a href="/logout">Logout</a></li>
|
<li><a href="/logout">Logout</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href="/#overview">About</a></li>
|
<li><a href="/#overview">About</a></li>
|
||||||
|
@ -27,10 +26,10 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Sitewide notificaton -->
|
<!-- Sitewide notificaton -->
|
||||||
<div class='header alert alert-warning alert-dismissible'>
|
<!--<div class='header alert alert-warning alert-dismissible'>
|
||||||
<strong>Tracman is going through a server migration and various technical issues. Sorry for the inconvienence! <br>You can encourage me to work on it by <a href="https://cash.me/$KeithIrwin">making a donation</a>.
|
<strong>Whoops!</strong> Tracman down right now. It will be fixed in a few days.
|
||||||
<a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a>
|
<a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a>
|
||||||
</div>
|
</div>-->
|
||||||
|
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<div class='header alert alert-danger alert-dismissible'>
|
<div class='header alert alert-danger alert-dismissible'>
|
||||||
|
|
Loading…
Reference in New Issue