Various updates
parent
9dd203750e
commit
51c46bc032
|
@ -1 +1 @@
|
|||
{ "_id" : { "$oid" : "56b020279f740067540f96e9" }, "googleID" : 1.044820980603112e+20, "slug" : "keith", "email" : "mail@keithirwin.us", "name" : "Keith", "created" : { "$date" : "2016-02-01T22:19:03.062-0500" }, "lastLogin" : { "$date" : "2016-03-11T02:00:47.868-0500" }, "last" : { "time" : { "$date" : "2016-03-11T04:29:49.046-0500" }, "spd" : 0, "dir" : 0, "lon" : -74.8288264, "lat" : 39.9087593 }, "settings" : { "showStreetview" : false, "showAlt" : true, "showSpeed" : true, "defaultZoom" : 11, "defaultMap" : "sat", "units" : "imperial" }, "isAdmin" : true, "isPro" : true }
|
||||
{ "_id" : { "$oid" : "56b020279f740067540f96e9" }, "googleID" : 1.044820980603112e+20, "slug" : "keith", "email" : "mail@keithirwin.us", "name" : "Keith", "created" : { "$date" : "2016-02-02T04:19:03.062+0100" }, "lastLogin" : { "$date" : "2016-03-19T22:59:48.941+0100" }, "last" : { "time" : { "$date" : "2016-03-19T23:58:20.990+0100" }, "spd" : 0, "dir" : 0, "lon" : -74.8288264, "lat" : 39.9087593 }, "settings" : { "showStreetview" : false, "showAlt" : true, "showSpeed" : true, "defaultZoom" : 11, "defaultMap" : "sat", "units" : "imperial" }, "isAdmin" : true, "isPro" : true }
|
||||
|
|
|
@ -22,7 +22,7 @@ passport.use(new GoogleStrategy({
|
|||
});
|
||||
done(null, user);
|
||||
} else { // No existing user with google auth
|
||||
if (req.session.passport.user) { // Creating new user
|
||||
if (req.session.passport) { // Creating new user
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
user.googleID = profile.id;
|
||||
user.lastLogin = Date.now();
|
||||
|
|
204
config/routes.js
204
config/routes.js
|
@ -13,11 +13,18 @@ app.use(bodyParser.urlencoded({
|
|||
}));
|
||||
app.use(bodyParser.json());
|
||||
|
||||
// Test authentication/admin
|
||||
function ensureAuthenticated(req,res,next) {
|
||||
function throwErr(req,err) {
|
||||
console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', (err.message||'')+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
}
|
||||
function ensureAuth(req,res,next) {
|
||||
if (req.isAuthenticated()) { return next(); }
|
||||
else { req.flash('error', 'You must be signed in to do that. <a href="/login">Click here to log in</a>. ');
|
||||
res.redirect('/'); }
|
||||
else {
|
||||
req.session.returnTo = req.path;
|
||||
req.flash('error', 'You must be signed in to do that. <a href="/login">Click here to log in</a>. ');
|
||||
res.redirect('/');
|
||||
}
|
||||
}
|
||||
function ensureAdmin(req,res,next) {
|
||||
if (req.user.isAdmin) { return next(); }
|
||||
|
@ -38,11 +45,10 @@ module.exports = function(app){
|
|||
.all(function(req,res,next){
|
||||
next();
|
||||
}).get(function(req,res){
|
||||
if (req.session.passport!=undefined) {
|
||||
if (req.session.passport) {
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error-message', err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
|
||||
if (err){ throwErr(req,err); }
|
||||
if (!user){ next(); }
|
||||
res.render('index.html', {
|
||||
user: user,
|
||||
error: req.flash('error')[0],
|
||||
|
@ -59,58 +65,49 @@ module.exports = function(app){
|
|||
}
|
||||
}).post(function(req,res){
|
||||
Request.findOne({email:req.body.email}, function(err, request) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message', err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
res.redirect('/');
|
||||
} else if (!err && request == null) { // Send new request
|
||||
if (err){ throwErr(req,err); }
|
||||
if (request){ // Already requested with this email
|
||||
req.flash('request-error', 'Invite already requested! ');
|
||||
res.redirect('/#get');
|
||||
} else { // Send new request
|
||||
request = new Request({
|
||||
name: req.body.name,
|
||||
email: req.body.email,
|
||||
beg: req.body.why,
|
||||
requestedTime: Date.now()
|
||||
}); request.save(function(err) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message', err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
res.redirect('/');
|
||||
} else {
|
||||
mail.mailgun.messages().send({
|
||||
from: 'Tracman Requests <requests@tracman.org>',
|
||||
to: 'Keith Irwin <tracman@keithirwin.us>',
|
||||
subject: 'New Tracman Invite request',
|
||||
html: '<p>'+req.body.name+' requested a Tracman invite. </p><p>'+req.body.why+'</p><p><a href="http://tracman.org/admin/requests">See all invites</a></p>',
|
||||
text: '\n'+req.body.name+' requested a Tracman invite. \n\n'+req.body.why+'\n\nhttp://tracman.org/admin/requests'
|
||||
}, function(err,body){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error-message', err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
}
|
||||
req.flash('request-success', 'Invite requested! ');
|
||||
res.redirect('/#get');
|
||||
});
|
||||
}
|
||||
if (err){ throwErr(req,err); }
|
||||
mail.mailgun.messages().send({
|
||||
from: 'Tracman Requests <requests@tracman.org>',
|
||||
to: 'Keith Irwin <tracman@keithirwin.us>',
|
||||
subject: 'New Tracman Invite request',
|
||||
html: '<p>'+req.body.name+' requested a Tracman invite. </p><p>'+req.body.why+'</p><p><a href="http://tracman.org/admin/requests">See all invites</a></p>',
|
||||
text: '\n'+req.body.name+' requested a Tracman invite. \n\n'+req.body.why+'\n\nhttp://tracman.org/admin/requests'
|
||||
}, function(err,body){
|
||||
if (err){ throwErr(req,err); }
|
||||
else { req.flash('request-success', 'Invite requested! '); }
|
||||
res.redirect('/#get');
|
||||
});
|
||||
});
|
||||
} else { // Already requested with this email
|
||||
req.flash('request-error', 'Invite alreay requested! ');
|
||||
res.redirect('/#get');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.route('/dashboard')
|
||||
.all(ensureAuthenticated, function(req,res,next){
|
||||
.all(ensureAuth, function(req,res,next){
|
||||
next();
|
||||
}).get(function(req,res){
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');}
|
||||
res.render('dashboard.html', {
|
||||
if (err){ throwErr(req,err); }
|
||||
if (!user){ next(); }
|
||||
else if (req.session.returnTo && req.query.rd) {
|
||||
res.redirect(req.session.returnTo);
|
||||
delete req.session.returnTo;
|
||||
} else { res.render('dashboard.html', {
|
||||
user: user,
|
||||
success: req.flash('success')[0],
|
||||
error: req.flash('error')[0]
|
||||
});
|
||||
}); }
|
||||
});
|
||||
}).post(function(req,res){
|
||||
User.findByIdAndUpdate(req.session.passport.user, {$set:{
|
||||
|
@ -125,53 +122,46 @@ module.exports = function(app){
|
|||
showStreetview: (req.body.showStreet)?true:false
|
||||
}
|
||||
}}, function(err, user){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
} else { req.flash('success', 'Settings updated. '); }
|
||||
if (err) { throwErr(req,err); }
|
||||
else { req.flash('success', 'Settings updated. '); }
|
||||
res.redirect('/dashboard');
|
||||
});
|
||||
});
|
||||
app.get('/validate', function(req,res){
|
||||
if (req.query.slug) { // validate unique slug
|
||||
User.findOne({slug:req.query.slug}, function(err, existingUser){
|
||||
User.findOne({slug:slug(req.query.slug)}, function(err, existingUser){
|
||||
if (existingUser && existingUser.id!==req.session.passport.user) { res.sendStatus(400); }
|
||||
else { res.sendStatus(200); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/trac', function(req,res,next){
|
||||
app.get('/trac', ensureAuth, function(req,res,next){
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
|
||||
if (user) { res.redirect('/trac/'+user.slug); }
|
||||
else { next(); }
|
||||
if (err){ throwErr(req,err); }
|
||||
if (!user){ next(); }
|
||||
else { res.redirect('/trac/'+user.slug+((req.url.indexOf('?')<0)?'':('?'+req.url.split('?')[1]))); }
|
||||
});
|
||||
});
|
||||
app.get('/trac/:slug', function(req,res,next){
|
||||
User.findOne({slug:req.params.slug}, function(err, tracuser) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
|
||||
if (err){ throwErr(req,err); }
|
||||
if (!tracuser){ next(); }
|
||||
else {
|
||||
res.render('trac.html', {
|
||||
api: secret.mapAPI,
|
||||
user: req.user,
|
||||
tracuser: tracuser,
|
||||
noHeader: req.query.noheader
|
||||
});
|
||||
}
|
||||
else { res.render('trac.html',{
|
||||
api: secret.mapAPI,
|
||||
user: req.user,
|
||||
tracuser: tracuser,
|
||||
noFooter: '1',
|
||||
noHeader: (req.query.noheader)?req.query.noheader.match(/\d/)[0]:'',
|
||||
disp: (req.query.disp)?req.query.disp.match(/\d/)[0]:'' // 0=map, 1=streetview, 2=both
|
||||
}); }
|
||||
});
|
||||
});
|
||||
app.get('/trac/id/:id', function(req,res){
|
||||
User.findById(req.params.id, function(err, user){
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
|
||||
res.redirect('/trac/'+user.slug);
|
||||
if (err){ throwErr(req,err); }
|
||||
if (!user){ next(); }
|
||||
else { res.redirect('/trac/'+user.slug+((req.url.indexOf('?')<0)?'':('?'+req.url.split('?')[1]))); }
|
||||
});
|
||||
});
|
||||
app.get('/invited/:invite', function(req,res,next){
|
||||
|
@ -180,8 +170,8 @@ module.exports = function(app){
|
|||
if (existingUser) { res.redirect('/login'); }
|
||||
else {
|
||||
Request.findById(req.params.invite, function(err, request) { // Check for granted invite
|
||||
if (err) { console.log('routes.js:125 ERROR: '+err); }
|
||||
if (!request.granted) { next(); }
|
||||
if (err) { throwErr(req,err); }
|
||||
if (!request) { next(); }
|
||||
else {
|
||||
user = new User({ // Create new user
|
||||
requestId: request._id,
|
||||
|
@ -197,19 +187,19 @@ module.exports = function(app){
|
|||
showStreetview: true
|
||||
}
|
||||
}); user.save(function(err) {
|
||||
if (err) { console.log('routes.js:141 ERROR: '+err); }
|
||||
if (err) { throwErr(req,err); }
|
||||
User.findOne({requestId:request._id}, function(err, user) {
|
||||
if (err) { console.log('routes.js:143 ERROR: '+err); }
|
||||
if (err) { throwErr(req,err); }
|
||||
if (user) {
|
||||
request.userId = user._id;
|
||||
request.save(function(err, raw){
|
||||
if (err) { console.log('routes.js:147 ERROR: '+err); }
|
||||
if (err){ throwErr(req,err); }
|
||||
});
|
||||
req.logIn(user, function(err) {
|
||||
if (err) { console.log('routes.js:150: logIn() ERROR: '+err); }
|
||||
if (err) { throwErr(req,err); }
|
||||
user.lastLogin = Date.now();
|
||||
user.save(function(err, raw) {
|
||||
if (err) { console.log('routes.js:153 ERROR: '+err); }
|
||||
if (err) { throwErr(req,err); }
|
||||
res.redirect('/login');
|
||||
});
|
||||
});
|
||||
|
@ -222,30 +212,27 @@ module.exports = function(app){
|
|||
});
|
||||
});
|
||||
|
||||
app.get('/android', ensureAuthenticated, function(req,res){
|
||||
app.get('/android', ensureAuth, function(req,res){
|
||||
res.redirect('https://play.google.com/store/apps/details?id=us.keithirwin.tracman');
|
||||
});
|
||||
app.get('/license', function(req,res){
|
||||
res.render('license.html', {user:req.user});
|
||||
});
|
||||
app.route('/pro')
|
||||
.all(ensureAuthenticated, function(req,res,next){
|
||||
.all(ensureAuth, function(req,res,next){
|
||||
next();
|
||||
}).get(function(req,res){
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
|
||||
res.render('pro.html', {user:user});
|
||||
if (err){ throwErr(req,err); }
|
||||
if (!user){ next(); }
|
||||
else { res.render('pro.html', {user:user}); }
|
||||
});
|
||||
}).post(function(req,res){
|
||||
User.findByIdAndUpdate(req.session.passport.user,
|
||||
{$set:{ isPro:true }},
|
||||
function(err, user){
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message', err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
} else { req.flash('success', 'You have been signed up for pro. '); }
|
||||
if (err){ throwErr(req,err); }
|
||||
else { req.flash('success','You have been signed up for pro. '); }
|
||||
res.redirect('/dashboard');
|
||||
}
|
||||
);
|
||||
|
@ -260,15 +247,13 @@ module.exports = function(app){
|
|||
email: (req.body.email)?req.body.email:req.user.email,
|
||||
suggestion: req.body.suggestion
|
||||
}, function (err, raw) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message',err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
} else { req.flash('success', 'Thanks for the suggestion! '); }
|
||||
if (err){ throwErr(req,err); }
|
||||
else { req.flash('success','Thanks for the suggestion! '); }
|
||||
res.redirect('/dashboard');
|
||||
});
|
||||
});
|
||||
app.route('/bug')
|
||||
.all(ensureAuthenticated, function(req,res,next){
|
||||
.all(ensureAuth, function(req,res,next){
|
||||
next();
|
||||
}).get(function(req,res){
|
||||
res.render('bug.html', {
|
||||
|
@ -284,27 +269,24 @@ module.exports = function(app){
|
|||
recreation: req.body.recreation,
|
||||
bug: req.body.bug
|
||||
}, function (err, raw) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error-message', err);
|
||||
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
|
||||
} else { req.flash('success', 'Thanks for the report! '); }
|
||||
if (err){ throwErr(req,err); }
|
||||
else { req.flash('success','Thanks for the report! '); }
|
||||
res.redirect('/dashboard');
|
||||
});
|
||||
});
|
||||
|
||||
// ADMIN
|
||||
app.route('/admin/requests')
|
||||
.all([ensureAuthenticated, ensureAdmin], function(req,res,next){
|
||||
.all([ensureAuth, ensureAdmin], function(req,res,next){
|
||||
next();
|
||||
}).get(function(req,res){
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err){ req.flash('error', err.message); }
|
||||
Request.find({}, function(err, requests){
|
||||
if (err) { console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err) { req.flash('error', err.message); }
|
||||
res.render('admin/requests.html', {
|
||||
user: user,
|
||||
noFooter: '1',
|
||||
requests: requests,
|
||||
success:req.flash('success')[0],
|
||||
error:req.flash('error')[0]
|
||||
|
@ -313,31 +295,27 @@ module.exports = function(app){
|
|||
});
|
||||
}).post(function(req,res){
|
||||
Request.findById(req.body.invite, function(err, request){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err){ req.flash('error', err.message); }
|
||||
mail.sendInvite(request, function (err, raw) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err) { req.flash('error', err.message); }
|
||||
request.granted = Date.now();
|
||||
request.save(function(err) {
|
||||
if (err) { console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err) { req.flash('error', err.message); }
|
||||
});
|
||||
req.flash('success', 'Invitation sent to <i>'+request.name+'</i>.');
|
||||
res.redirect('/admin/requests');
|
||||
});
|
||||
});
|
||||
});
|
||||
app.get('/admin/users', [ensureAuthenticated, ensureAdmin], function(req,res){
|
||||
app.get('/admin/users', [ensureAuth, ensureAdmin], function(req,res){
|
||||
User.findById(req.session.passport.user, function(err, user){
|
||||
if (err){ console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err){ req.flash('error', err.message); }
|
||||
User.find({}, function(err, users){
|
||||
if (err) { console.log(err);
|
||||
req.flash('error', err.message); }
|
||||
if (err) { req.flash('error', err.message); }
|
||||
res.render('admin/users.html', {
|
||||
user: user,
|
||||
users: users,
|
||||
noFooter: '1',
|
||||
success:req.flash('success')[0],
|
||||
error:req.flash('error')[0]
|
||||
});
|
||||
|
@ -360,12 +338,12 @@ module.exports = function(app){
|
|||
app.get('/auth/google/callback', passport.authenticate('google', {
|
||||
failureRedirect: '/',
|
||||
failureFlash: true,
|
||||
successRedirect: '/dashboard',
|
||||
successRedirect: '/dashboard?rd=1',
|
||||
successFlash: true
|
||||
} ));
|
||||
app.get('/auth/google/idtoken', passport.authenticate('google-id-token'), function (req,res) {
|
||||
if (!req.user) {res.sendStatus(401);}
|
||||
else {res.send(req.user);}
|
||||
if (!req.user) { res.sendStatus(401); }
|
||||
else { res.send(req.user); }
|
||||
} );
|
||||
|
||||
}
|
||||
|
|
11
package.json
11
package.json
|
@ -23,14 +23,17 @@
|
|||
"slug": "^0.9.1",
|
||||
"socket.io": "^1.4.4"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"devDependencies": {
|
||||
"chai": "^3.5.0",
|
||||
"chai-http": "^2.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "test.js",
|
||||
"start": "node server.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/keith24/tracman-server.git"
|
||||
"url": "git+https://github.com/tracman-org/server.git"
|
||||
},
|
||||
"keywords": [
|
||||
"tracking",
|
||||
|
@ -41,7 +44,7 @@
|
|||
"license": "MIT",
|
||||
"README": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/keith24/tracman-server/issues"
|
||||
"url": "https://tracman.org/bug"
|
||||
},
|
||||
"homepage": "http://tracman.org/"
|
||||
"homepage": "https://tracman.org/"
|
||||
}
|
||||
|
|
21
server.js
21
server.js
|
@ -25,6 +25,7 @@ app.use(session({
|
|||
saveUninitialized: true,
|
||||
resave: true
|
||||
}));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: true
|
||||
}));
|
||||
|
@ -47,10 +48,12 @@ var handle404 = function(err,req,res,next) {
|
|||
var handle500 = function(err,req,res,next) {
|
||||
res.render('error.html', {code:500});
|
||||
};
|
||||
app.use(crash.handle404(handle404));
|
||||
app.use(crash.handle500(handle500));
|
||||
crash.trapRoute(app);
|
||||
crash.handle(app, handle404, handle500);
|
||||
if (secret.url.substring(0,16)!='http://localhost') {
|
||||
app.use(crash.handle404(handle404));
|
||||
app.use(crash.handle500(handle500));
|
||||
crash.trapRoute(app);
|
||||
crash.handle(app, handle404, handle500);
|
||||
}
|
||||
|
||||
// Check for tracking users
|
||||
function checkForUsers(room) {
|
||||
|
@ -68,6 +71,7 @@ function checkForUsers(room) {
|
|||
}
|
||||
}
|
||||
|
||||
// Sockets
|
||||
io.on('connection', function(socket) {
|
||||
|
||||
socket.on('room', function(room) {
|
||||
|
@ -75,10 +79,7 @@ io.on('connection', function(socket) {
|
|||
if (room.slice(0,4)!='app-'){
|
||||
User.findById({_id:room}, function(err, user) {
|
||||
if (err) { console.log(err); }
|
||||
if (user) {
|
||||
io.to(room).emit('trac', user.last);
|
||||
io.to('app-'+room).emit('activate', 'true');
|
||||
}
|
||||
if (user) { io.to('app-'+room).emit('activate','true'); }
|
||||
});
|
||||
} else {
|
||||
checkForUsers(room.slice(4));
|
||||
|
@ -122,8 +123,8 @@ passport.deserializeUser(function(id, done) {
|
|||
});
|
||||
|
||||
// SERVE
|
||||
http.listen(secret.httpPort, function(){
|
||||
console.log('Listening for http on port '+secret.httpPort.toString());
|
||||
http.listen(62054, function(){
|
||||
console.log('Listening for http on port 62054');
|
||||
checkForUsers();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* Resets, Clears & Defaults */
|
||||
|
||||
*, *:after, *:before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
@ -76,20 +75,15 @@ h1, h2, h3, p {
|
|||
z-index: 6;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4 { font-weight: 600; }
|
||||
h1 {
|
||||
font-size: 40px;
|
||||
line-height: 46px;
|
||||
font-weight: 600;
|
||||
}
|
||||
font-size: 48px;
|
||||
line-height: 46px; }
|
||||
h2 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
font-weight: 600;
|
||||
}
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
font-size: 40px;
|
||||
line-height: 36px; }
|
||||
h3 { font-size: 28px; }
|
||||
h4 { font-size: 20px; }
|
||||
|
||||
.red { color: #fb6e3d; }
|
||||
|
||||
|
|
|
@ -174,8 +174,8 @@
|
|||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
.disclaimer a, disclaimer:hover {
|
||||
color:inherit;
|
||||
.disclaimer a, .disclaimer a:hover {
|
||||
color:#fb6e3d;
|
||||
}
|
||||
|
||||
.get {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 552 KiB After Width: | Height: | Size: 552 KiB |
|
@ -0,0 +1,35 @@
|
|||
var chai = require('chai'),
|
||||
chaiHttp = require('chai-http'),
|
||||
server = require('./server'),
|
||||
should = chai.should();
|
||||
chai.use(chaiHttp);
|
||||
|
||||
describe('Routes', function() {
|
||||
|
||||
it('Displays homepage', function(done){
|
||||
chai.request(server)
|
||||
.get('/')
|
||||
.end(function(err,res){
|
||||
res.should.have.status(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Displays robots.txt', function(done){
|
||||
chai.request(server)
|
||||
.get('/robots.txt')
|
||||
.end(function(err,res){
|
||||
res.should.have.status(200);
|
||||
res.should.be.text;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Displays a tracpage', function(done){
|
||||
chai.request(server)
|
||||
.get('/trac/keith')
|
||||
.end(function(err,res){
|
||||
res.should.have.status(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -1,12 +1,13 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | Invite Requests{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
{% block head %}
|
||||
<style>
|
||||
.container { max-width:90%; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Requests</h1>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | Users{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
{% block head %}
|
||||
<style>
|
||||
.container { max-width:90%; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Users</h1>
|
||||
|
|
101
views/bug.html
101
views/bug.html
|
@ -1,71 +1,64 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | Bug Report{% endblock %}
|
||||
{% block title %}{{ super() }} | Bug Report{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Submit a Bug Report</h1>
|
||||
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Submit a Bug Report</h1>
|
||||
<p>You can use this form to submit a bug report. You can also <a href="https://github.com/Tracman-org/Server/issues/new">post the issue on github</a>. Or maybe you'd like to <a href="/suggestion">suggest a feature</a> instead? </p>
|
||||
|
||||
<p>You can use this form to submit a bug report. Maybe you'd like to <a href="/suggestion">suggest a feature</a> instead? </p>
|
||||
<script src="/static/js/validator.min.js"></script>
|
||||
<form id='suggestions-form' class='col-lg-10 col-lg-offset-1 form-horizontal' role="form" method="POST" data-toggle="validator">
|
||||
|
||||
<script src="/static/js/validator.min.js"></script>
|
||||
<form id='suggestions-form' class='col-lg-10 col-lg-offset-1 form-horizontal' role="form" method="POST" data-toggle="validator">
|
||||
|
||||
<div class='form-group' id='error-message' title="If you recieved an error message, put it here. An error message may be added automatically. ">
|
||||
<label class='control-label col-sm-2 col-lg-3' for="errorMessage">Error message (if any) </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="errorMessage" rows="3" maxlength="2400" {% if errorMessage.length %}disabled{% endif %}>{{ errorMessage }}</textarea>
|
||||
</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 class='form-group' id='error-message' title="If you recieved an error message, put it here. An error message may be added automatically. ">
|
||||
<label class='control-label col-sm-2 col-lg-3' for="errorMessage">Error message (if any) </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="errorMessage" rows="3" maxlength="2400" {% if errorMessage.length %}disabled{% endif %}>{{ errorMessage }}</textarea>
|
||||
</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 class='form-group' id='recreation' title="Help me recreate the issue. ">
|
||||
<label class='control-label col-sm-2 col-lg-3' for="recreation">What were you doing when this happened? </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="recreation" rows="4" maxlength="2400"></textarea>
|
||||
</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 class='form-group' id='recreation' title="Help me recreate the issue. ">
|
||||
<label class='control-label col-sm-2 col-lg-3' for="recreation">What were you doing when this happened? </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="recreation" rows="4" maxlength="2400"></textarea>
|
||||
</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 class='form-group' id='bug' title="Describe the problem here. ">
|
||||
<label class='control-label col-sm-2 col-lg-3' for="bug">What happened? </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="bug" rows="4" maxlength="2400"></textarea>
|
||||
</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 class='form-group' id='bug' title="Describe the problem here. ">
|
||||
<label class='control-label col-sm-2 col-lg-3' for="bug">What happened? </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="bug" rows="4" maxlength="2400"></textarea>
|
||||
</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 class='form-group' id='name' title="Put your name here if you want. ">
|
||||
<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"><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 class='form-group' id='name' title="Put your name here if you want. ">
|
||||
<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"><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 class='form-group' id='email' title="Put an email address if you want a reply. ">
|
||||
<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="That's not an email address"><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 class='form-group' id='email' title="Put an email address if you want a reply. ">
|
||||
<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="That's not an email address"><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 class='form-group flexbox' id='buttons'>
|
||||
<button type="submit" class='btn yellow'>SUBMIT</button>
|
||||
<a class='btn' href="/dashboard">nevermind</a>
|
||||
</div>
|
||||
</form>
|
||||
<!--
|
||||
col-xs-4 col-xs-offset-1 col-lg-3 col-lg-offset-2
|
||||
col-xs-4 col-xs-offset-1 col-lg-3 col-lg-offset-1
|
||||
-->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
<div class='form-group flexbox' id='buttons'>
|
||||
<button type="submit" class='btn yellow'>SUBMIT</button>
|
||||
<a class='btn' href="/dashboard">nevermind</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,28 +1,34 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | Dashboard{% endblock %}
|
||||
{% block title %}{{ super() }} | Dashboard{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<style>
|
||||
.google-play {
|
||||
width:150px;
|
||||
border: #fbc93d solid 1px;
|
||||
border-radius:10px; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
<style>
|
||||
.google-play {
|
||||
width:150px;
|
||||
border: #fbc93d solid 1px;
|
||||
border-radius:10px; }
|
||||
</style>
|
||||
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Welcome{% if user.name %}, {{ user.name }}{% endif %}!</h1>
|
||||
<p>To view your location, use this link: <a href="/trac/{{ user.slug }}">http://tracman.org/trac/{{ user.slug }}</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. </p>
|
||||
<pre><iframe src="https://tracman.org/trac/{{ user.slug }}?noheader=1" width="90%" style="height:90vh;"></iframe></pre>
|
||||
|
||||
</div>
|
||||
<br>
|
||||
<div class='container'>
|
||||
<h2>App</h2>
|
||||
<p>Click the button below to download the app from the google play store, if you haven't already. </p>
|
||||
<p><a href="https://play.google.com/store/apps/details?id=us.keithirwin.tracman&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-AC-global-none-all-co-pr-py-PartBadges-Oct1515-1"><img class='google-play' alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge.png" /></a></p>
|
||||
<p>Without the app running, your location won't update. But you can also set your location to this device's geolocation by clicking the button below. </p>
|
||||
<p><button id='manual-set' class='btn' style="display:block; margin:auto;" onclick="setLocation()"><i class="fa fa-map-marker"></i> Update location manually</button></p>
|
||||
|
||||
</div>
|
||||
<br>
|
||||
<div 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">
|
||||
|
@ -130,11 +136,10 @@
|
|||
|
||||
{% 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="/suggestion">suggestion</a> or <a href="/bug">bug report</a>? </p>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
|
||||
<script>
|
||||
var socket = io.connect();
|
||||
|
@ -151,10 +156,11 @@
|
|||
spd: (pos.coords.speed||0)
|
||||
});
|
||||
alert('Location updated! ');
|
||||
location.reload();
|
||||
}, function(err){
|
||||
alert('ERROR: '+err);
|
||||
}, { enableHighAccuracy:true });
|
||||
}
|
||||
} else { alert('Unable to set location. '); }
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | {{ code }} Error{% endblock %}
|
||||
{% block title %}{{ super() }} | {{ code }} Error{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<img style="width:100%;" src="https://http.cat/{{ code }}.jpg" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<img style="width:100%;" src="https://http.cat/{{ code }}.jpg" />
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
|
||||
{% block main %}
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<link href="/static/css/index.css" rel="stylesheet">
|
||||
<script src="/static/js/index.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% include 'templates/header.html' %}
|
||||
|
||||
<section class='splash dark' id='splash' name='splash'>
|
||||
{% block main %}
|
||||
<script src="/static/js/index.js"></script>
|
||||
|
||||
<section class='splash dark' id='splash'>
|
||||
<div class='container'>
|
||||
<h1>Tracman</h1>
|
||||
<h2>Let friends track your GPS location in realtime</h2>
|
||||
<h3>Let friends track your GPS location in realtime</h3>
|
||||
<a class='btn' href="#" data-scrollto="overview">More info<i class='fa fa-angle-down'></i></a>
|
||||
{% if not user %}
|
||||
<a class='btn' href="#" data-scrollto="get">Request invite<i class='fa fa-angle-down'></i></a>
|
||||
|
@ -21,46 +23,46 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section class='overview dark' id='overview' name='overview'>
|
||||
<section class='overview dark' id='overview'>
|
||||
<div class='container'>
|
||||
<div>
|
||||
<i class='fa fa-mobile'></i>
|
||||
<h2>Easy-to-use</h2>
|
||||
<h3>Easy-to-use</h3>
|
||||
<p>Download the android app and log in. Then send your friends a link with a map showing your live location. </p>
|
||||
</div>
|
||||
<div>
|
||||
<i class='fa fa-bolt'></i>
|
||||
<h2>Realtime</h2>
|
||||
<h3>Realtime</h3>
|
||||
<p>Your location updates every second for all the world to see. </p>
|
||||
</div>
|
||||
<div>
|
||||
<i class='fa fa-usd'></i>
|
||||
<h2>Free</h2>
|
||||
<h3>Free</h3>
|
||||
<p>It's free, but you can <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=hypergeek14%40gmail%2ecom&lc=US&item_name=Tracman¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted">donate</a> if you want to help with server expenses. </p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class='feature app dark' id='app' name='app'>
|
||||
<section class='feature app dark' id='app'>
|
||||
<div class='container'>
|
||||
<img src="/static/img/style/phone.png" alt="Mobile phone">
|
||||
<div>
|
||||
<h1>The App</h1>
|
||||
<h2>The App</h2>
|
||||
<p>Tracman uses an android app to recieve GPS location of your device. Sorry, there's no iPhone version yet. </p>
|
||||
<ul>
|
||||
<li>
|
||||
<i class='fa fa-toggle-on'></i>
|
||||
<h3>On/off switch</h3>
|
||||
<h4>On/off switch</h4>
|
||||
<p>If you need to go undercover, just turn tracman off with the flip of a switch. </p>
|
||||
</li>
|
||||
<li>
|
||||
<i class='fa fa-cog'></i>
|
||||
<h3>Settings</h3>
|
||||
<h4>Settings</h4>
|
||||
<p>Change your settings to show a less accurate location, if you want an air of mystery. </p>
|
||||
</li>
|
||||
<li>
|
||||
<i class='fa fa-battery-3'></i>
|
||||
<h3>Saves energy</h3>
|
||||
<h4>Saves energy</h4>
|
||||
<p>If nobody's tracking you, tracman won't needlessly drain your battery. </p>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -68,26 +70,26 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section class='feature tracpage dark' id='tracpage' name='tracpage'>
|
||||
<section class='feature tracpage dark' id='tracpage'>
|
||||
<div class='container'>
|
||||
<img src="/static/img/style/laptop.png" alt="Laptop">
|
||||
<div>
|
||||
<h1>The Map</h1>
|
||||
<h2>The Map</h2>
|
||||
<p>You'll get a simple webpage with a map to send to friends. <a href="/trac/keith">Click here for a demo</a>. </p>
|
||||
<ul>
|
||||
<li>
|
||||
<i class='fa fa-hand-o-right'></i>
|
||||
<h3>Easy</h3>
|
||||
<h4>Easy</h4>
|
||||
<p>Just send a link to whomever you want. Bam, now they know exactly where you are. </p>
|
||||
</li>
|
||||
<li>
|
||||
<i class='fa fa-map-marker'></i>
|
||||
<h3>Precise</h3>
|
||||
<h4>Precise</h4>
|
||||
<p>Map updates in realtime using the fancy-pants websockets protocol. </p>
|
||||
</li>
|
||||
<li>
|
||||
<i class='fa fa-cogs'></i>
|
||||
<h3>Customizable</h3>
|
||||
<h4>Customizable</h4>
|
||||
<p>You can change some things. Not a lot yet, but I am always adding features. </p>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -95,10 +97,10 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section class='disclaimer light' id='disclaimer' name='disclaimer'>
|
||||
<section class='disclaimer light' id='disclaimer'>
|
||||
<div class='container'>
|
||||
<h1>Warning! </h1>
|
||||
<h2>I assume no responsibility for anything whatsoever. </h2>
|
||||
<h2>Warning! </h2>
|
||||
<h3>I assume no responsibility for anything whatsoever. </h3>
|
||||
<p>If you haven't realized it already, there are a lot of reasons why publishing your location online could be a bad idea. </p>
|
||||
<ul>
|
||||
<li>You get caught cheating</li>
|
||||
|
@ -111,14 +113,14 @@
|
|||
</section>
|
||||
|
||||
{% if not user %}
|
||||
<section class='get light' id='get' name='get'>
|
||||
<section class='get light' id='get'>
|
||||
<div class='container'>
|
||||
<h1>Hook me up!</h1>
|
||||
<h2>Right now, Tracman is invite-only. You can beg me for access here. </h2>
|
||||
<form id='invite-form' role="form" method="post">
|
||||
<h2>Hook me up!</h2>
|
||||
<h3>Right now, Tracman is invite-only. You can beg me for access here. </h3>
|
||||
<form id='invite-form' method="post">
|
||||
<label class='input'><span>Name</span><input type="text" name="name" required></label>
|
||||
<label class='input'><span>Email address</span><input type="email" name="email" required></label>
|
||||
<label class='message'><span>Why you deserve beta access</span><textarea id='why' name="why" required></textarea></label>
|
||||
<label class='message'><span>Why you deserve beta access (optional)</span><textarea id='why' name="why"></textarea></label>
|
||||
<label class='checkbox'><input type="checkbox" name="disclaimer" required><span>I've read the <a href="#" data-scrollto="disclaimer">scary warning</a>. </span></label>
|
||||
<label class='submit'>
|
||||
{% if inviteSuccess.length > 0 %}
|
||||
|
@ -133,7 +135,5 @@
|
|||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | License{% endblock %}
|
||||
{% block title %}{{ super() }} | License{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
<section class='dark'>
|
||||
|
||||
<div class='container'>
|
||||
<h2>The MIT License (MIT)</h2>
|
||||
<h3>Copyright © 2016 Keith Irwin</h3>
|
||||
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h2>The MIT License (MIT)</h2>
|
||||
<h3>Copyright © 2016 Keith Irwin</h3>
|
||||
<p>Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions: </p>
|
||||
|
||||
<p>Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions: </p>
|
||||
<p>The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software. </p>
|
||||
|
||||
<p>The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software. </p>
|
||||
|
||||
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. </p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. </p>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,46 +1,43 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | Pro{% endblock %}
|
||||
{% block title %}{{ super() }} | Pro{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
<section class='dark'>
|
||||
|
||||
<div class='container'>
|
||||
<h1>Tracman Pro</h1>
|
||||
<h3>A word from the developer</h3>
|
||||
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Tracman Pro</h1>
|
||||
<h3>A word from the developer</h3>
|
||||
<p>Hi Folks, </p>
|
||||
|
||||
<p>Hi Folks, </p>
|
||||
<p>Glad you're enjoying my website and app. I made the whole thing, from front to backend,
|
||||
and I'm really proud of it! However, I'm a long-haul trucker by day and coding is just a hobby.
|
||||
I don't make any money off this website, and I pay the server fees out of my own pocket. Do you
|
||||
pity me enough to donate some money by <a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=_flow&SESSION=56toCNZRvXj-_J6kC_5D258zMwjyU7hLvxKFQXsIG5_nzVlAhEw2VLFf7K0&dispatch=5885d80a13c0db1f8e263663d3faee8defcd6970d4fd9d661117ac2649af92bb">paypal</a>
|
||||
or <a href="bitcoin:1GXbuM398Y2tYwSaQhNQHXWF1AN6GeRgQh?label=tracman">bitcoin</a>? </p>
|
||||
|
||||
<p>Glad you're enjoying my website and app. I made the whole thing, from front to backend,
|
||||
and I'm really proud of it! However, I'm a long-haul trucker by day and coding is just a hobby.
|
||||
I don't make any money off this website, and I pay the server fees out of my own pocket. Do you
|
||||
pity me enough to donate some money by <a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=_flow&SESSION=56toCNZRvXj-_J6kC_5D258zMwjyU7hLvxKFQXsIG5_nzVlAhEw2VLFf7K0&dispatch=5885d80a13c0db1f8e263663d3faee8defcd6970d4fd9d661117ac2649af92bb">paypal</a>
|
||||
or <a href="bitcoin:1GXbuM398Y2tYwSaQhNQHXWF1AN6GeRgQh?label=tracman">bitcoin</a>? </p>
|
||||
<p>To make a little money off this service, I'm going to be offering a pro version with more
|
||||
features. It'll be cheap, probably $1 or $2 per month. However, while Tracman is in beta,
|
||||
you can beta test the pro version too. Be sure to inform me about any <a href="/bug">bugs</a>
|
||||
you encounter or <a href="/suggestion">suggestions</a> you have. And keep in mind that at some
|
||||
point, when we launch out of beta, Tracman Pro will <em>not</em> be free and <strong>you will
|
||||
lose your pro membership</strong> unless start paying for it.
|
||||
|
||||
<p>To make a little money off this service, I'm going to be offering a pro version with more
|
||||
features. It'll be cheap, probably $1 or $2 per month. However, while Tracman is in beta,
|
||||
you can beta test the pro version too. Be sure to inform me about any <a href="/bug">bugs</a>
|
||||
you encounter or <a href="/suggestion">suggestions</a> you have. And keep in mind that at some
|
||||
point, when we launch out of beta, Tracman Pro will <em>not</em> be free and <strong>you will
|
||||
lose your pro membership</strong> unless start paying for it.
|
||||
<p>That said, just click the button below to test out the pro features. Keep in mind, they are
|
||||
as <a href="/#disclaimer">unstable</a> as the rest of this product.
|
||||
|
||||
<p>That said, just click the button below to test out the pro features. Keep in mind, they are
|
||||
as <a href="/#disclaimer">unstable</a> as the rest of this product.
|
||||
<p>Cheers, <br>
|
||||
<a href="https://keithirwin.us/">Keith Irwin</a></p>
|
||||
|
||||
<p>Cheers, <br>
|
||||
<a href="https://keithirwin.us/">Keith Irwin</a></p>
|
||||
<form class='row flexbox' action="#" method="POST">
|
||||
{% if user.isPro %}
|
||||
<div class='alert alert-success'><i class="fa fa-check-circle"></i> You are already pro! </div>
|
||||
{% else %}
|
||||
<button type="submit" class='btn yellow'>GO PRO</button>
|
||||
{% endif %}
|
||||
<a class='btn' href="/dashboard">go home</a>
|
||||
</form>
|
||||
|
||||
<form class='row flexbox' action="" method="POST">
|
||||
{% if user.isPro %}
|
||||
<div class='alert alert-success'><i class="fa fa-check-circle"></i> You are already pro! </div>
|
||||
{% else %}
|
||||
<button type="submit" class='btn yellow'>GO PRO</button>
|
||||
{% endif %}
|
||||
<a class='btn' href="/dashboard">go home</a>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,52 +1,48 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | Suggestion{% endblock %}
|
||||
{% block title %}{{ super() }} | Suggestion{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'templates/header.html' %}
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Suggest a Feature</h1>
|
||||
|
||||
<section class='dark'>
|
||||
<div class='container'>
|
||||
<h1>Suggest a Feature</h1>
|
||||
<p>You can use this form to suggest new features. Or maybe you need to <a href="/bug">submit a bug report</a> instead? </p>
|
||||
|
||||
<p>You can use this form to suggest new features. Or maybe you need to <a href="/bug">submit a bug report</a> instead? </p>
|
||||
<script src="/static/js/validator.min.js"></script>
|
||||
<form id='suggestions-form' class='col-lg-10 col-lg-offset-1 form-horizontal' role="form" method="POST" data-toggle="validator">
|
||||
|
||||
<script src="/static/js/validator.min.js"></script>
|
||||
<form id='suggestions-form' class='col-lg-10 col-lg-offset-1 form-horizontal' role="form" method="POST" data-toggle="validator">
|
||||
|
||||
<div class='form-group' id='suggestion'>
|
||||
<label class='control-label col-sm-2 col-lg-3' for="suggestion">What feature could improve Tracman? </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="suggestion" rows="5" required maxlength="2400" data-error="You have to make a suggestion! "></textarea>
|
||||
</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 class='form-group' id='suggestion'>
|
||||
<label class='control-label col-sm-2 col-lg-3' for="suggestion">What feature could improve Tracman? </label>
|
||||
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
|
||||
<textarea class='form-control' name="suggestion" rows="5" required maxlength="2400" data-error="You have to make a suggestion! "></textarea>
|
||||
</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 class='form-group' id='name' title="Put your name here if you want. ">
|
||||
<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"><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 class='form-group' id='name' title="Put your name here if you want. ">
|
||||
<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"><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 class='form-group' id='email' title="Put an email address if you want a reply. ">
|
||||
<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="That's not an email address"><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 class='form-group' id='email' title="Put an email address if you want a reply. ">
|
||||
<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="That's not an email address"><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 class='form-group flexbox' id='buttons'>
|
||||
<button type="submit" class='btn yellow'>SUBMIT</button>
|
||||
<a class='btn' href="/dashboard">nevermind</a>
|
||||
</div>
|
||||
</form>
|
||||
<div class='form-group flexbox' id='buttons'>
|
||||
<button type="submit" class='btn yellow'>SUBMIT</button>
|
||||
<a class='btn' href="/dashboard">nevermind</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% include 'templates/footer.html' %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{% block head %}
|
||||
<title>{% block title %}Tracman{% endblock %}</title>
|
||||
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
|
@ -13,7 +14,7 @@
|
|||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
|
||||
<link rel="shortcut icon" sizes="16x16 & 32x32 & 48x48" type="image/x-icon" href="/static/img/icon/by/16-32-48.ico">
|
||||
<link rel="shortcut icon" sizes="16x16 32x32 48x48" type="image/x-icon" href="/static/img/icon/by/16-32-48.ico">
|
||||
<link rel="icon apple-touch-icon" sizes="32x32" type="image/png" href="/static/img/icon/by/32.png">
|
||||
<link rel="icon apple-touch-icon" sizes="57x57" type="image/png" href="/static/img/icon/by/57.png">
|
||||
<link rel="icon apple-touch-icon" sizes="72x72" type="image/png" href="/static/img/icon/by/72.png">
|
||||
|
@ -30,6 +31,9 @@
|
|||
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
|
||||
|
||||
{% endblock %}
|
||||
{% if not noHeader %}<link href="/static/css/header.css" rel="stylesheet">{% endif %}
|
||||
{% if not noFooter %}<link href="/static/css/footer.css" rel="stylesheet">{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
@ -39,8 +43,10 @@
|
|||
<a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
|
||||
{% if not noHeader %}{% include 'templates/header.html' %}{% endif %}
|
||||
{% block main %}Loading... {% endblock %}
|
||||
{% if not noFooter %}{% include 'templates/footer.html' %}{% endif %}
|
||||
|
||||
<script>
|
||||
(function(t,r,a,c,m,o,n){t['GoogleAnalyticsObject']=m;t[m]=t[m]||function(){
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
<link href="/static/css/footer.css" rel="stylesheet">
|
||||
|
||||
<footer class='footer'>
|
||||
<div class='left'>
|
||||
<p>Website and app by <a href="https://keithirwin.us/">Keith Irwin</a>.
|
||||
<br>Design by <a href="http://boag.online/blog/maglev-free-responsive-website-template" target="_blank">Fraser Boag</a>. </p>
|
||||
<br>Design by <a href="http://boag.online/blog/maglev-free-responsive-website-template">Fraser Boag</a>. </p>
|
||||
</div>
|
||||
<div class='right'>
|
||||
Share:
|
||||
<a href="https://twitter.com/home?status=Show%20your%20location%20to%20friends%20in%20realtime%20at%20http://tracman.org/" target="_blank"><i class="fa fa-twitter"></i></a>
|
||||
<a href="https://www.facebook.com/sharer/sharer.php?u=http://tracman.org/" target="_blank"><i class="fa fa-facebook"></i></a>
|
||||
<a href="https://www.reddit.com/submit?title=Show%20your%20location%20to%20friends%20in%20realtime%20at%20&url=http://tracman.org/" target="_blank"><i class="fa fa-reddit-alien"></i></a>
|
||||
<br>Donate:
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=hypergeek14%40gmail%2ecom&lc=US&item_name=Tracman¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"><i class="fa fa-paypal"></i></a>
|
||||
<a href="https://www.facebook.com/sharer/sharer.php?u=https://tracman.org/" target="_blank"><i class="fa fa-facebook"></i></a>
|
||||
<a href="https://twitter.com/home?status=Show%20your%20location%20to%20friends%20in%20realtime%20at%20https://tracman.org/" target="_blank"><i class="fa fa-twitter"></i></a>
|
||||
<a href="https://www.reddit.com/submit?title=Show%20your%20location%20to%20friends%20in%20realtime%20at%20&url=https://tracman.org/" target="_blank"><i class="fa fa-reddit-alien"></i></a>
|
||||
<br>Contribute:
|
||||
<a href="https://github.com/Tracman-org/Server"><i class="fa fa-github"></i></a>
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=hypergeek14%40gmail%2ecom&lc=US&item_name=Tracman¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted" target="_blank"><i class="fa fa-paypal"></i></a>
|
||||
<a href="bitcoin:1GXbuM398Y2tYwSaQhNQHXWF1AN6GeRgQh?label=tracman"><i class="fa fa-btc"></i></a>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<link href="/static/css/header.css" rel="stylesheet">
|
||||
<script src="/static/js/header.js"></script>
|
||||
|
||||
<header>
|
||||
<a href="/"><h1 class='logo'><img src="/static/img/style/logo-28.png" class='icon'>Tracman</h1></a>
|
||||
<a href="/"><span class='logo'><img class='icon' src="/static/img/style/logo-28.png" alt="+">Tracman</span></a>
|
||||
<div class='hamburger hamburger--slider' aria-label="Menu" aria-controls="navigation">
|
||||
<div class='hamburger-box'>
|
||||
<div class='hamburger-inner'></div>
|
||||
|
|
303
views/trac.html
303
views/trac.html
|
@ -1,51 +1,63 @@
|
|||
{% extends 'templates/base.html' %}
|
||||
{% block title %}Tracman | {{ tracuser.name }}{% endblock %}
|
||||
{% block title %}{{ super() }} | {{ tracuser.name }}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<link href="/static/css/trac.css" rel="stylesheet">
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<link href="/static/css/trac.css" rel="stylesheet">
|
||||
<style>
|
||||
.wrap { top:{% if not noHeader %}58{% else %}0{% endif %}px;}
|
||||
{% if tracuser.settings.showStreetview %}
|
||||
#map, #pano {display:inline-block;}
|
||||
img#panoImg { width:100%; height:100%; }
|
||||
|
||||
{% if tracuser.settings.showStreetview and disp!='0' and disp!='1' %}
|
||||
/* show both */
|
||||
@media (orientation: landscape) {
|
||||
#map, #pano {
|
||||
width:50%;
|
||||
height:99%;
|
||||
#map, #pano {
|
||||
display:inline-block;
|
||||
width:50%;
|
||||
height:99%;
|
||||
}
|
||||
#pano { float:right; }
|
||||
}
|
||||
#pano {float:right;}
|
||||
}
|
||||
@media (orientation: portrait) {
|
||||
#map, #pano {
|
||||
@media (orientation: portrait) {
|
||||
#map, #pano {
|
||||
width:100%;
|
||||
height:50%;
|
||||
}
|
||||
#pano { bottom:0; }
|
||||
}
|
||||
{% elif tracuser.settings.showStreetview and disp=='1' %}
|
||||
/* show streetview */
|
||||
#pano {
|
||||
width:100%;
|
||||
height:50%;
|
||||
}
|
||||
#pano {bottom:0}
|
||||
}
|
||||
height:100%;}
|
||||
#map {display:none;}
|
||||
{% else %}
|
||||
#map {
|
||||
width:100%;
|
||||
height:100%;}
|
||||
#pano {display:none;}
|
||||
/* show map */
|
||||
#map {
|
||||
width:100%;
|
||||
height:100%;}
|
||||
#pano {display:none;}
|
||||
{% endif %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% if not noHeader %}
|
||||
{% include 'templates/header.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% block main %}
|
||||
<div class='wrap'>
|
||||
|
||||
{% if not tracuser.last.time %}
|
||||
<div class='centered alert alert-warning'>
|
||||
<strong>No Location Found</strong>
|
||||
<br>This user hasn't updated their location yet!
|
||||
<br>If this is your page, maybe you want to <a href="/android">download the app</a>.
|
||||
<b>No Location Found</b>
|
||||
{% if user.id == tracuser.id %}
|
||||
<br>You can <a href="#" onclick="setLocation()">click here to set use this device's location</a>.
|
||||
<br>Maybe you also want to <a href="/android">download the android app</a>.
|
||||
{% else %}
|
||||
<br>This user hasn't updated their location yet!
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div id='map'><i class='loading fa fa-refresh fa-spin'></i></div>
|
||||
{% if tracuser.settings.showStreetview %}
|
||||
<div id='pano'><i class='loading fa fa-refresh fa-spin'></i></div>
|
||||
{% if tracuser.settings.showStreetview and not noStreetview.length %}
|
||||
<div id='pano'><img id='panoImg' src="https://maps.googleapis.com/maps/api/streetview?size=800x800&location={{ tracuser.last.lat }},{{ tracuser.last.lon }}&fov=90&heading={{ tracuser.last.dir|default(0) }}&key={{ api }}" alt="Street view image"></div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -58,7 +70,25 @@
|
|||
var tracuserid = {{ tracuser._id | dump | safe }},
|
||||
settings = JSON.parse('{{ tracuser.settings | dump | safe }}'),
|
||||
last = JSON.parse('{{ tracuser.last | dump | safe }}'),
|
||||
noHeader = '{{ noHeader | dump | safe }}';
|
||||
noHeader = {{ noHeader | dump | safe }},
|
||||
disp = {{ disp | dump | safe }};
|
||||
|
||||
// Set location manually
|
||||
function setLocation() {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(pos){
|
||||
socket.emit('app', {
|
||||
usr: '{{ user.id }}',
|
||||
lat: pos.coords.latitude,
|
||||
lon: pos.coords.longitude,
|
||||
spd: (pos.coords.speed||0)
|
||||
});
|
||||
alert('Location updated! ');
|
||||
}, function(err){
|
||||
alert('ERROR: '+err);
|
||||
}, { enableHighAccuracy:true });
|
||||
} else { alert('Unable to set location. '); }
|
||||
}
|
||||
|
||||
var getAltitude = function(location, elevator, cb){
|
||||
elevator = elevator || new google.maps.ElevationService;
|
||||
|
@ -71,140 +101,119 @@
|
|||
});
|
||||
}
|
||||
|
||||
var map, marker, pano, dir, lat, lon, spd, alt, newLocation, elevator;
|
||||
var map, marker, elevator;
|
||||
function initMap() {
|
||||
map = new google.maps.Map(document.getElementById('map'),{
|
||||
zoom: settings.defaultZoom,
|
||||
streetViewControl: false,
|
||||
zoomControlOptions: {position: google.maps.ControlPosition.LEFT_TOP},
|
||||
mapTypeId: (settings.defaultMap=='road')?google.maps.MapTypeId.ROADMAP:google.maps.MapTypeId.HYBRID
|
||||
});
|
||||
marker = new google.maps.Marker({
|
||||
map: map,
|
||||
draggable: false
|
||||
});
|
||||
if (settings.showStreetview) {
|
||||
pano = new google.maps.StreetViewPanorama( document.getElementById('pano'), {
|
||||
// Create map
|
||||
if (disp!='1' || !settings.showStreetview) {
|
||||
map = new google.maps.Map( document.getElementById('map'), {
|
||||
center: new google.maps.LatLng( last.lat, last.lon ),
|
||||
panControl: false,
|
||||
zoomControl: false,
|
||||
addressControl: false,
|
||||
linksControl: false
|
||||
draggable: false,
|
||||
zoom: settings.defaultZoom,
|
||||
streetViewControl: false,
|
||||
zoomControlOptions: {position: google.maps.ControlPosition.LEFT_TOP},
|
||||
mapTypeId: (settings.defaultMap=='road')?google.maps.MapTypeId.ROADMAP:google.maps.MapTypeId.HYBRID
|
||||
});
|
||||
marker = new google.maps.Marker({
|
||||
position: { lat:last.lat, lng:last.lon },
|
||||
title: {{ tracuser.name | dump | safe }},
|
||||
map: map,
|
||||
draggable: false
|
||||
});
|
||||
|
||||
// Create iFrame logo
|
||||
if (noHeader.length) {
|
||||
var logoDiv = document.createElement('div');
|
||||
logoDiv.className = 'map-logo';
|
||||
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
|
||||
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
|
||||
'Tracman</a>';
|
||||
map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
|
||||
}
|
||||
|
||||
// Create update time block
|
||||
var timeDiv = document.createElement('div');
|
||||
timeDiv.className = 'tim';
|
||||
if (last.time) {
|
||||
timeDiv.innerHTML = 'location updated '+new Date(last.time).toLocaleString();
|
||||
}
|
||||
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
|
||||
|
||||
// Create speed block
|
||||
if (settings.showSpeed) {
|
||||
var speedSign = document.createElement('div'),
|
||||
speedLabel = document.createElement('div'),
|
||||
speedText = document.createElement('div'),
|
||||
speedUnit = document.createElement('div');
|
||||
speedLabel.className = 'spd-label';
|
||||
speedText.className = 'spd';
|
||||
speedUnit.className = 'spd-unit';
|
||||
speedSign.className = 'spd-sign';
|
||||
speedText.innerHTML = (settings.units=='imperial')?(parseFloat(last.spd)*2.23694).toFixed():last.spd.toFixed();
|
||||
speedLabel.innerHTML = 'SPEED';
|
||||
speedUnit.innerHTML = (settings.units=='imperial')?'m.p.h.':'k.p.h.';
|
||||
speedSign.appendChild(speedLabel);
|
||||
speedSign.appendChild(speedText);
|
||||
speedSign.appendChild(speedUnit);
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(speedSign);
|
||||
}
|
||||
|
||||
// Create altitude block
|
||||
if (settings.showAlt) {
|
||||
var elevator = new google.maps.ElevationService;
|
||||
var altitudeSign = document.createElement('div'),
|
||||
altitudeLabel = document.createElement('div'),
|
||||
altitudeText = document.createElement('div'),
|
||||
altitudeUnit = document.createElement('div');
|
||||
altitudeLabel.className = 'alt-label';
|
||||
altitudeText.className = 'alt';
|
||||
altitudeUnit.className = 'alt-unit';
|
||||
altitudeSign.className = 'alt-sign';
|
||||
altitudeText.innerHTML = '';
|
||||
altitudeLabel.innerHTML = 'ALTITUDE';
|
||||
getAltitude(new google.maps.LatLng(last.lat,last.lon), elevator, function(alt) {
|
||||
if (alt) { altitudeText.innerHTML = (settings.units=='imperial')?(alt*3.28084).toFixed():alt.toFixed(); }
|
||||
});
|
||||
altitudeUnit.innerHTML = (settings.units=='imperial')?'feet above sea level':'meters above sea level';
|
||||
altitudeSign.appendChild(altitudeLabel);
|
||||
altitudeSign.appendChild(altitudeText);
|
||||
altitudeSign.appendChild(altitudeUnit);
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(altitudeSign);
|
||||
}
|
||||
}
|
||||
|
||||
// Create iFrame logo
|
||||
if (noHeader) {
|
||||
var logoDiv = document.createElement('div');
|
||||
logoDiv.className = 'map-logo';
|
||||
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
|
||||
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
|
||||
'Tracman</a>';
|
||||
map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
|
||||
}
|
||||
|
||||
// Create update time block
|
||||
var timeDiv = document.createElement('div');
|
||||
timeDiv.className = 'tim';
|
||||
if (last.time) {
|
||||
timeDiv.innerHTML = 'location updated '+new Date(last.time).toLocaleString();
|
||||
}
|
||||
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
|
||||
|
||||
// Create speed block
|
||||
if (settings.showSpeed) {
|
||||
var speedSign = document.createElement('div'),
|
||||
speedLabel = document.createElement('div'),
|
||||
speedText = document.createElement('div'),
|
||||
speedUnit = document.createElement('div');
|
||||
speedLabel.className = 'spd-label';
|
||||
speedText.className = 'spd';
|
||||
speedUnit.className = 'spd-unit';
|
||||
speedSign.className = 'spd-sign';
|
||||
speedText.innerHTML = '';
|
||||
speedLabel.innerHTML = 'SPEED';
|
||||
if (last.spd) {
|
||||
speedText.innerHTML = (settings.units=='imperial')?
|
||||
(parseFloat(last.spd)*2.23694).toFixed():last.spd;
|
||||
// Create streetview
|
||||
if (settings.showStreetview && disp!='0') {
|
||||
document.getElementById('panoImg').src='https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').outerWidth()+'x'+$('#pano').outerHeight()+'&location='+last.lat+','+last.lon+'&fov=90&heading='+(last.dir||0)+'&key={{ api }}';
|
||||
}
|
||||
if (settings.units=='imperial') {
|
||||
speedUnit.innerHTML = 'm.p.h.';
|
||||
} else {
|
||||
speedUnit.innerHTML = 'k.p.h.';}
|
||||
speedSign.appendChild(speedLabel);
|
||||
speedSign.appendChild(speedText);
|
||||
speedSign.appendChild(speedUnit);
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(speedSign);
|
||||
}
|
||||
|
||||
// Create altitude block
|
||||
if (settings.showAlt) {
|
||||
elevator = new google.maps.ElevationService;
|
||||
var altitudeSign = document.createElement('div'),
|
||||
altitudeLabel = document.createElement('div'),
|
||||
altitudeText = document.createElement('div'),
|
||||
altitudeUnit = document.createElement('div');
|
||||
altitudeLabel.className = 'alt-label';
|
||||
altitudeText.className = 'alt';
|
||||
altitudeUnit.className = 'alt-unit';
|
||||
altitudeSign.className = 'alt-sign';
|
||||
altitudeText.innerHTML = '';
|
||||
altitudeLabel.innerHTML = 'ALTITUDE';
|
||||
if (last.lon && settings.showAlt) {
|
||||
newLocation = new google.maps.LatLng(last.lat, last.lon);
|
||||
getAltitude(newLocation, elevator, function(alt) {
|
||||
if (alt) {
|
||||
alt = (settings.units=='imperial')?alt*3.28084:alt;
|
||||
altitudeText.innerHTML = alt.toFixed();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settings.units=='imperial') {
|
||||
altitudeUnit.innerHTML = 'feet above sea level';
|
||||
} else {
|
||||
altitudeUnit.innerHTML = 'meters above sea level';}
|
||||
altitudeSign.appendChild(altitudeLabel);
|
||||
altitudeSign.appendChild(altitudeText);
|
||||
altitudeSign.appendChild(altitudeUnit);
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(altitudeSign);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sockets
|
||||
socket.on('connect', function(){
|
||||
socket.emit('room', tracuserid);
|
||||
});
|
||||
|
||||
var dir, lat, lon, spd, alt, newLocation;
|
||||
socket.on('trac', function(loc){
|
||||
spd = (settings.units=='imperial')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd);
|
||||
dir = parseFloat(loc.dir);
|
||||
lat = parseFloat(loc.lat);
|
||||
lon = parseFloat(loc.lon);
|
||||
newLocation = new google.maps.LatLng(loc.lat, loc.lon);
|
||||
$('.tim').text('location updated '+new Date(loc.time).toLocaleString());
|
||||
if (settings.showSpeed) {
|
||||
$('.spd').text(spd.toFixed());
|
||||
}
|
||||
if (settings.showAlt) {
|
||||
getAltitude(newLocation, elevator, function(alt) {
|
||||
if (alt) {
|
||||
alt = (settings.units=='imperial')?alt*3.28084:alt;
|
||||
$('.alt').text(alt.toFixed());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map.setCenter(newLocation);
|
||||
marker.setPosition(newLocation);
|
||||
if (settings.showStreetview) {
|
||||
if (pano.position != newLocation) {
|
||||
pano.setPosition(newLocation);
|
||||
if (spd>0) {
|
||||
pano.setPov({pitch:0,heading:dir});
|
||||
}
|
||||
newLocation = new google.maps.LatLng(loc.lat,loc.lon)
|
||||
if (disp!='1' || !settings.showStreetview) {
|
||||
$('.tim').text('location updated '+new Date(loc.time).toLocaleString());
|
||||
if (settings.showSpeed) { $('.spd').text(spd.toFixed()); }
|
||||
if (settings.showAlt) {
|
||||
getAltitude(newLocation, elevator, function(alt) {
|
||||
if (alt) { $('.alt').text((settings.units=='imperial')?(alt*3.28084).toFixed():alt.toFixed()); }
|
||||
});
|
||||
}
|
||||
map.setCenter(newLocation);
|
||||
marker.setPosition(newLocation);
|
||||
}
|
||||
if (settings.showStreetview && disp!='0') {
|
||||
document.getElementById('panoImg').src='https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').width()+'x'+$('#pano').height()+'&location='+loc.lat+','+loc.lon+'&fov=90&heading='+dir+'&key={{ api }}';
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue