Merge develop branch into master for release 0.5.0
commit
564dc54666
15
README.md
15
README.md
|
@ -1,11 +1,11 @@
|
|||
# Tracman
|
||||
###### v 0.4.3
|
||||
###### v 0.5.0
|
||||
|
||||
node.js application to display a map with user's location.
|
||||
|
||||
## Installation
|
||||
```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
|
||||
|
@ -14,8 +14,19 @@ $ git clone https://github.com/Tracman-org/Server.git && (cd server && exec npm
|
|||
$ npm start
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Tracman will be updated according to [this branching model](http://nvie.com/posts/a-successful-git-branching-model).
|
||||
|
||||
## 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
|
||||
|
||||
* 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'),
|
||||
crypto = require('crypto'),
|
||||
secret = require('./secrets.js'),
|
||||
|
@ -30,7 +32,7 @@ passport.use(new GoogleStrategy({
|
|||
|
||||
// User not found
|
||||
else /* create user */ {
|
||||
var user = new User();
|
||||
user = new User();
|
||||
user.googleID = profile.id;
|
||||
user.name = profile.displayName;
|
||||
user.email = profile.emails[0].value;
|
||||
|
@ -42,7 +44,7 @@ passport.use(new GoogleStrategy({
|
|||
// user.isPro = false;
|
||||
// user.isAdmin = false;
|
||||
var cbc = 2;
|
||||
var successMessage, failMessage
|
||||
var successMessage, failMessage;
|
||||
|
||||
// Generate slug
|
||||
(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){
|
||||
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},
|
||||
email: String,
|
||||
slug: {type:String, required:true, unique:true},
|
||||
|
@ -29,3 +31,5 @@ module.exports = mongoose.model('User', {
|
|||
},
|
||||
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'),
|
||||
User = require('../models/user.js');
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
var router = require('express').Router(),
|
||||
'use strict';
|
||||
|
||||
const router = require('express').Router(),
|
||||
passport = require('passport');
|
||||
|
||||
router.get('/login', function(req,res){
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
var router = require('express').Router(),
|
||||
mw = require('../middleware.js'),
|
||||
secret = require('../secrets.js'),
|
||||
User = require('../models/user.js');
|
||||
|
||||
'use strict';
|
||||
|
||||
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('/')
|
||||
.get(function(req,res,next){
|
||||
.get(function(req,res,next){
|
||||
|
||||
// Logged in
|
||||
if (req.session.passport&&req.session.passport.user) {
|
||||
if ( req.session.passport && req.session.passport.user ){
|
||||
// Get user
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err){ mw.throwErr(req,err); }
|
||||
|
@ -21,9 +29,7 @@ router.route('/')
|
|||
success: req.flash('succcess')[0]
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
// 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;
|
|
@ -1,7 +1,8 @@
|
|||
var router = require('express').Router(),
|
||||
'use strict';
|
||||
|
||||
const router = require('express').Router(),
|
||||
mw = require('../middleware.js'),
|
||||
secret = require('../secrets.js'),
|
||||
slug = require('slug'),
|
||||
secrets = require('../secrets.js'),
|
||||
User = require('../models/user.js');
|
||||
|
||||
// Show map
|
||||
|
@ -44,8 +45,8 @@ router.get('/:slug?', function(req,res,next){
|
|||
} else {
|
||||
if (user && !mapuser) { mapuser = user; }
|
||||
res.render('map.html', {
|
||||
api: secret.mapAPI,
|
||||
mapuser: mapuser,
|
||||
mapApi: secrets.googleMapsAPI,
|
||||
user: user,
|
||||
noFooter: '1',
|
||||
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;
|
|
@ -1,4 +1,6 @@
|
|||
var router = require('express').Router(),
|
||||
'use strict';
|
||||
|
||||
const router = require('express').Router(),
|
||||
mw = require('../middleware.js'),
|
||||
slug = require('slug'),
|
||||
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",
|
||||
"version": "0.4.3",
|
||||
"version": "0.5.0",
|
||||
"description": "Tracks user's GPS location",
|
||||
"main": "server.js",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.15.0",
|
||||
"body-parser": "^1.17.1",
|
||||
"connect-flash": "^0.1.1",
|
||||
"cookie-parser": "^1.4.1",
|
||||
"cookie-session": "^2.0.0-alpha.1",
|
||||
"express": "^4.13.3",
|
||||
"express": "^4.15.2",
|
||||
"kerberos": "0.0.17",
|
||||
"moment": "^2.12.0",
|
||||
"mongodb": "^2.1.4",
|
||||
"mongoose": "^4.3.5",
|
||||
"mongoose": "^4.9.0",
|
||||
"node-jose": "^0.8.0",
|
||||
"nunjucks": "^2.3.0",
|
||||
"passport": "^0.3.2",
|
||||
|
@ -37,12 +37,7 @@
|
|||
"test": "mocha test.js",
|
||||
"start": "node 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'",
|
||||
"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'"
|
||||
"update": "sudo n stable && sudo npm update --save && sudo npm prune"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* IMPORTS */ { var
|
||||
'use strict';
|
||||
|
||||
/* IMPORTS */
|
||||
const
|
||||
express = require('express'),
|
||||
bodyParser = require('body-parser'),
|
||||
cookieParser = require('cookie-parser'),
|
||||
|
@ -11,8 +14,9 @@
|
|||
User = require('./config/models/user.js'),
|
||||
app = express(),
|
||||
http = require('http').Server(app),
|
||||
io = require('socket.io')(http);
|
||||
}
|
||||
io = require('socket.io')(http),
|
||||
sockets = require('./config/sockets.js');
|
||||
|
||||
|
||||
/* SETUP */ {
|
||||
/* Database */ mongoose.connect(secret.mongoSetup, {
|
||||
|
@ -59,6 +63,9 @@
|
|||
}
|
||||
|
||||
/* Routes */ {
|
||||
app.get('/favicon.ico', function(req,res){
|
||||
res.redirect('/static/img/icon/by/16-32-48.ico');
|
||||
});
|
||||
app.use('/',
|
||||
require('./config/routes/index.js'),
|
||||
require('./config/routes/auth.js'),
|
||||
|
@ -103,91 +110,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Sockets */ {
|
||||
sockets.init(io);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 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
|
||||
http.listen(secret.port, function(){
|
||||
console.log(
|
||||
|
@ -195,7 +125,15 @@
|
|||
'Listening at '+secret.url+
|
||||
'\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%;
|
||||
}
|
||||
|
||||
/* Alerts */
|
||||
.centered.alert {
|
||||
text-align:center;
|
||||
position: absolute;
|
||||
|
@ -17,16 +18,13 @@ body {
|
|||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
/* Map and streetview */
|
||||
#map, #pano {position:relative;}
|
||||
#pano {float:right;}
|
||||
.loading {
|
||||
font-size:7em;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -56px 0 0 -56px;
|
||||
}
|
||||
img#panoImg { width:100%; height:100%; }
|
||||
#notset {display:none}
|
||||
|
||||
/* Tracman logo */
|
||||
.map-logo {
|
||||
margin-left: -75px;
|
||||
background: rgba(0,0,0,.7);
|
||||
|
@ -35,6 +33,7 @@ body {
|
|||
}
|
||||
.map-logo a { color: #fbc93d; }
|
||||
|
||||
/* Timestamp */
|
||||
.tim {
|
||||
color: #000;
|
||||
font-size: 12px;
|
||||
|
@ -43,6 +42,9 @@ body {
|
|||
background-color: rgba(255,255,255,.7);
|
||||
}
|
||||
|
||||
/*TODO: Make signs smaller on mobile */
|
||||
|
||||
/* Speed sign */
|
||||
.spd {
|
||||
font-size: 32px;
|
||||
height: 40px;}
|
||||
|
@ -55,6 +57,7 @@ body {
|
|||
margin: 10px;
|
||||
background-color: #FFF;
|
||||
}
|
||||
/* Altitude sign */
|
||||
.alt-unit, .spd-unit { font-size:12px; }
|
||||
.alt-label, .spd-label {
|
||||
font-size:18px;
|
||||
|
@ -71,3 +74,11 @@ body {
|
|||
margin: 10px;
|
||||
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(){
|
||||
|
||||
// Open drawer with hamburger
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
jQuery.extend(jQuery.easing,{
|
||||
easeInOutExpo: function(x, t, b, c, d){
|
||||
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 %}
|
328
views/map.html
328
views/map.html
|
@ -5,48 +5,7 @@
|
|||
{{super()}}
|
||||
<link href="/static/css/map.css" rel="stylesheet">
|
||||
<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;}
|
||||
img#panoImg { width:100%; height:100%; }
|
||||
|
||||
{% if mapuser.settings.showStreetview and disp!='0' and disp!='1' %}
|
||||
/* show both */
|
||||
|
@ -83,201 +42,6 @@
|
|||
|
||||
{% 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 id='map'></div>
|
||||
|
@ -321,14 +85,13 @@
|
|||
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
|
||||
<script src="/static/js/bundle.js"></script>
|
||||
<script src="https://maps.googleapis.com/maps/api/js?key={{api}}&callback=gmapsCb" async defer></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="https://maps.googleapis.com/maps/api/js?key={{mapApi}}&callback=gmapsCb" async defer></script>
|
||||
<script>
|
||||
|
||||
/* Variables */ {
|
||||
var wpid, map, pano, sv, marker, elevator,
|
||||
sock = io.connect(),
|
||||
var wpid, map, pano, sv, marker, elevator,
|
||||
socket = io('//'+window.location.hostname),
|
||||
mapuserid = {{mapuser._id |dump|safe}},
|
||||
userid{% if user._id %} = {{user._id |dump|safe}}{% endif %},
|
||||
settings = JSON.parse('{{mapuser.settings |dump|safe}}'),
|
||||
|
@ -339,24 +102,31 @@
|
|||
panoElem = document.getElementById('pano');
|
||||
}
|
||||
|
||||
// Connect to socket.io
|
||||
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+)
|
||||
if (!'onhashchange' in window) {
|
||||
if (!confirm("location.hash won't work in IE<9. If you don't know how to fix this, click cancel. ")){
|
||||
window.open("https://whatbrowser.org/");
|
||||
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}.`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
function parseLoc(loc) {
|
||||
loc.spd = (settings.units=='standard')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd)
|
||||
|
@ -474,30 +244,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
|
||||
sock.on('trac', function(loc) {
|
||||
socket.on('get', function(loc) {
|
||||
//console.log(`Received location: ${loc.lat}, ${loc.lon}`);
|
||||
|
||||
loc = parseLoc(loc);
|
||||
if (disp!='1' || !settings.showStreetview) {
|
||||
$('.tim').text('location updated '+loc.time);
|
||||
|
@ -531,11 +281,16 @@
|
|||
lon: pos.coords.longitude,
|
||||
spd: (pos.coords.speed||0)
|
||||
}
|
||||
sock.emit('app',newloc);
|
||||
socket.broadcast.emit('app', newloc);
|
||||
toggleMaps(newloc);
|
||||
}, function(err) {
|
||||
console.log('done getting position');
|
||||
if (err) { console.log('ERROR: '+err); }
|
||||
if (err) {
|
||||
alert("Unable to set location.");
|
||||
io.emit('log',err.message);
|
||||
console.error(err.message); }
|
||||
else {
|
||||
//console.log('Set position',pos);
|
||||
}
|
||||
}, { enableHighAccuracy:true });
|
||||
}
|
||||
}
|
||||
|
@ -563,10 +318,13 @@
|
|||
lon: pos.coords.longitude,
|
||||
spd: (pos.coords.speed||0)
|
||||
};
|
||||
sock.emit('app',newloc);
|
||||
socket.broadcast.emit('app',newloc);
|
||||
toggleMaps(newloc);
|
||||
}, function(err){
|
||||
alert('Failed to track: \n'+err);
|
||||
if (err) {
|
||||
alert("Unable to track location.");
|
||||
console.log(err.message);
|
||||
}
|
||||
}, { enableHighAccuracy:true });
|
||||
}
|
||||
}
|
||||
|
@ -588,7 +346,7 @@
|
|||
usr: userid,
|
||||
lat:0, lon:0, spd:0
|
||||
}
|
||||
sock.emit('app',newloc);
|
||||
socket.broadcast.emit('app',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 %}
|
||||
{% if not noFooter %}{% include 'templates/footer.html' %}{% endif %}
|
||||
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
(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),
|
||||
|
@ -59,6 +60,18 @@
|
|||
ga('require','linkid');
|
||||
ga('send','pageview');
|
||||
</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>
|
||||
</html>
|
||||
|
|
|
@ -11,10 +11,9 @@
|
|||
<ul>
|
||||
{% if user %}
|
||||
<li><a href="/map/{{user.slug}}">Map</a></li>
|
||||
<li><a href="/map#share">Share</a></li>
|
||||
<li><a href="/map#settings">Settings</a></li>
|
||||
<li><a href="/settings">Settings</a></li>
|
||||
{% 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>
|
||||
{% else %}
|
||||
<li><a href="/#overview">About</a></li>
|
||||
|
@ -27,10 +26,10 @@
|
|||
</header>
|
||||
|
||||
<!-- Sitewide notificaton -->
|
||||
<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>.
|
||||
<!--<div class='header alert alert-warning alert-dismissible'>
|
||||
<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>
|
||||
</div>
|
||||
</div>-->
|
||||
|
||||
{% if error %}
|
||||
<div class='header alert alert-danger alert-dismissible'>
|
||||
|
@ -42,4 +41,4 @@
|
|||
<strong><i class="fa fa-check-circle"></i> Success!</strong> {{ success | safe }}
|
||||
<a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue