Updates to the website to remove Yaks and AP classes; Updates to the admin site to support user management (not working fully yet).

This commit is contained in:
Wynne Crisman
2016-07-20 15:11:55 -07:00
parent 83a831736a
commit 3340dc7e34
30 changed files with 1400 additions and 1666 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ public/emailFailures.txt
sessions/
config/db.js
.idea/workspace.xml
.idea/

414
app.js
View File

@@ -1,414 +0,0 @@
//NOT USED!!!
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
//var bodyParser = require('body-parser'); //Dup?
var nodeMailer = require('nodeMailer');
var bodyParser = require('body-parser');
var phantom = require('node-phantom');
var fs = require('fs');
var rootPath = path.join(__dirname, 'public');
var config = require('./config');
var moment = require('moment');
var methodOverride = require("method-override");
var session = require("express-session");
var passport = require("passport");
var localStrategy = require("passport-local");
var app = express();
app.use(logger('dev'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(methodOverride('X-HTTP-Method-Override'));
app.use(session({secret: 'au*2(_io?MajesticPeakMountainBoarding', saveUninitialized: true, resave: true}));
app.use(passport.initialize());
app.use(passport.session());
app.use(favicon(__dirname + '/public/images/Chicken.ico'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
//Ensure we have an endsWith method in String.
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
/*
//Check for all calls to content pages with a password attached and log it in the password's counter.
app.use(function(req, res, next) {
if(req.path.endsWith('.html')) {
if(req.query.Password) {
incrementPwdUseCount(req.query.Password);
}
}
next();
});
*/
app.use(express.static(rootPath, {dotfiles: 'deny', index: false}));
//app.use('/', routes);
app.use('/FrameworkController.java', function(req, res) {
console.log("In /FrameworkController.java");
var requestParam = req.query.Request;
if(requestParam == 'CreateId') {
res.type('json');
res.send({result: 0});
}
else {
console.log('unexpected value');
res.status(400).send('Unexpected Param');
}
});
//Handle the getting a brief and contacting us.
var smtpTransport = nodeMailer.createTransport({host: config.smtpHost, port: config.smtpPort, secure: true, ignoreTLS: false, requiresAuth: true, auth: {user: config.smtpUser, pass: config.smtpPassword}});
/*
//TEST CODE!!!//
try {
var name = "Wynne Crisman";
var email = "wynne@petitteton.com";
var textPath = rootPath + '/email/downloadBreifText.txt';
var htmlPath = rootPath + '/email/downloadBriefHtml.txt';
var signaturePath = rootPath + '/email/emailSignature.jpg';
var params = {from: config.fromAddress, to: email, subject: "Payback Brief", text: {path: textPath}, html: {path: htmlPath}, attachments: [{filename:'emailSignature.jpg', cid: 'emailSignature', path: signaturePath}]};
smtpTransport.sendMail(params, function(error, response) {
if(error) {
console.log("Error: " + error);
}
else {
console.log("Successfully sent the email - not an error.");
}
});
}
catch(e) {
console.log(e);
}
//END TEST//
*/
/*
//Setup the passwords used by users to access the content. Allows us to track who has used the site when and how much.
//Note: This is mostly for marketing purposes so it won't be very secure at all (no hashing, salting, SSL, or anything), and it allows the search engines to bypass it to the content.
var pwdData;
try {
if(fs.existsSync('pwdData.json')) {
pwdData = JSON.parse(fs.readFileSync('pwdData.json', 'utf8'));
}
else {
pwdData = [];
pwdData.push({pwd: 'zerotoone'});
pwdData.push({pwd: 'zephyr'});
pwdData.push({pwd: 'borealis'});
pwdData.push({pwd: 'gyroscope'});
pwdData.push({pwd: 'colnago'});
pwdData.push({pwd: 'derosa'});
pwdData.push({pwd: 'wwww&w'});
pwdData.push({pwd: 'catalyst'});
fs.writeFileSync('pwdData.json', JSON.stringify(pwdData), 'utf8');
}
} catch(e) {console.log(e);}
function writePwdData() {
try {
fs.writeFileSync('pwdData.json', JSON.stringify(pwdData), 'utf8');
} catch(e) {console.log(e);}
}
function incrementPwdUseCount(password) {
//Note: This is mostly for marketing purposes so it won't be very secure at all (no hashing, salting, SSL, or anything), and it allows the search engines to bypass it to the content.
try {
if(password) {
var index;
var found = false;
//Convert the password from base64.
password = new Buffer(password, 'base64').toString('utf-8');
//Identify which password was used (note: could use a map, but realistically with so few it is pointless complexity).
for(index = 0; !found && index < pwdData.length; index++) {
if(pwdData[index].pwd == password) {
//Track the number of times a user requests a content page.//
if(pwdData[index].accessCount) pwdData[index].accessCount++;
else pwdData[index].accessCount = 1;
writePwdData();
found = true;
}
}
}
} catch(e) {console.log(e);}
}
app.use('/RequestBrief/', function(req, res) {
try {
var firstName = req.body.FirstName;
var lastName = req.body.LastName;
var email = req.body.Email;
var isPartnership = req.body.PartnershipInterest;
var isInvestment = req.body.InvestmentInterest;
var isOther = req.body.OtherInterest;
var textPath = rootPath + '/email/downloadBriefText.txt';
var htmlPath = rootPath + '/email/downloadBriefHtml.txt';
var signaturePath = rootPath + '/email/emailSignature.jpg';
var params = {from: config.fromAddress, to: email, subject: "Payback Brief", text: {path: textPath}, html: {path: htmlPath}, attachments: [{filename:'emailSignature.jpg', cid: 'emailSignature', path: signaturePath}]};
smtpTransport.sendMail(params, function(error, response) {
try {
if(error) {
console.log("Received an error while sending the download brief email to the user. " + error);
fs.appendFile(rootPath + '/emailFailures.txt', JSON.stringify(params) + '\n', function(err) {if(err) {console.log("Failed to write email data to file! (request brief)");}});
}
else {
params = {from: config.fromAddress, to: config.contactUsRecipient, subject: "Downloaded Brief", text: "A user has requested the Payback brief.\n\nFirst Name: " + firstName + "\nLast Name: " + lastName + "\nEmail: " + email + "\nPartnership: " + isPartnership + "\nInvestment: " + isInvestment + "\nOther: " + isOther};
smtpTransport.sendMail(params, function(error, response) {
if(error) {
try {
console.log("Received an error while sending the request brief email to the admin. " + error);
fs.appendFile(rootPath + '/emailFailures.txt', JSON.stringify(params) + '\n', function(err) {if(err) {console.log("Failed to write email data to file! (request brief)");}});
} catch(e) {console.log(e);}
}
});
}
res.status(200).send('success');
} catch(e) {console.log(e);}
});
} catch(e) {console.log(e);}
});
app.use('/RequestFinancials/', function(req, res) {
try {
var firstName = req.body.FirstName;
var lastName = req.body.LastName;
var email = req.body.Email;
var phone = req.body.Phone;
var company = req.body.Company;
var message = req.body.Message;
var isPartnership = req.body.PartnershipInterest;
var isInvestment = req.body.InvestmentInterest;
var isOther = req.body.OtherInterest;
var textPath = rootPath + '/email/downloadFinancialsText.txt';
var htmlPath = rootPath + '/email/downloadFinancialsHtml.txt';
var textContents = fs.readFileSync(textPath, "UTF8");
var htmlContents = fs.readFileSync(htmlPath, "UTF8");
var signaturePath = rootPath + '/email/emailSignature.jpg';
textContents = textContents.replace("%%NAME%%", firstName);
htmlContents = htmlContents.replace("%%NAME%%", firstName);
var params = {from: config.fromAddress, to: email, subject: "Payback Financials", text: textContents, html: htmlContents, attachments: [{filename:'emailSignature.jpg', cid: 'emailSignature', path: signaturePath}]};
smtpTransport.sendMail(params, function(error, response) {
try {
if(error) {
console.log("Received an error while sending the request financials email to the user. " + error);
fs.appendFile(rootPath + '/emailFailures.txt', JSON.stringify(params) + '\n', function(err) {if(err) {console.log("Failed to write email data to file! (request financials)");}});
}
else {
params = {from: config.fromAddress, to: config.contactUsRecipient, subject: "Downloaded Financials", text: "A user has requested Payback's financials.\n\nFirst Name: " + firstName + "\nLast Name: " + lastName + "\nEmail: " + email + "\nPhone: " + phone + "\nCompany: " + company + "\nPartnership: " + isPartnership + "\nInvestment: " + isInvestment + "\nOther: " + isOther + "\nMessage: " + message};
smtpTransport.sendMail(params, function(error, response) {
if(error) {
try {
console.log("Received an error while sending the request financials email to the admin. " + error);
fs.appendFile(rootPath + '/emailFailures.txt', JSON.stringify(params) + '\n', function(err) {if(err) {console.log("Failed to write email data to file! (request financials)");}});
} catch(e) {console.log(e);}
}
});
}
res.status(200).send('success');
} catch(e) {console.log(e);}
});
} catch(e) {console.log(e);}
});
*/
app.use('/ContactUs', function(req, res) {
try {
var firstName = req.body.FirstName;
var lastName = req.body.LastName;
var email = req.body.Email;
var message = req.body.Text;
var params = {from: config.fromAddress, to: config.contactUsRecipient, subject: "Contact Us", text: "A user has commented via the Petit Teton website.\n\nFirst Name: " + firstName + "\nLast Name: " + lastName + "\nEmail: " + email + "\n" + message};
smtpTransport.sendMail(params, function(error, response) {
if(error) {
try {
console.log("Received an error while sending the contact us email to the admin. " + error);
fs.appendFile(rootPath + '/emailFailures.txt', JSON.stringify(params) + '\n', function(err) {if(err) {console.log("Failed to write email data to file! (contact us)");}});
} catch(e) {console.log(e);}
}
});
res.status(200).send('success');
} catch(e) {console.log(e);}
});
/*
app.use('/LoginUser', function(req, res) {
//Note: This is mostly for marketing purposes so it won't be very secure at all (no hashing, salting, SSL, or anything), and it allows the search engines to bypass it to the content.
try {
var password = req.body.Password;
if(password) {
var index;
var found = false;
//Convert the password from base64.
password = new Buffer(password, 'base64').toString('utf-8');
//Identify which password was used (note: could use a map, but realistically with so few it is pointless complexity).
for(index = 0; !found && index < pwdData.length; index++) {
if(pwdData[index].pwd == password) {
//Track the time of the first and last login.
if(pwdData[index].firstLogin) pwdData[index].lastLogin = new Date();
else pwdData[index].firstLogin = new Date();
writePwdData();
found = true;
}
}
if(found) {
//Notify the client they have logged in.
res.status(200).send('success');
}
else {
res.status(200).send('failed');
}
}
else {
res.status(200).send('failed');
}
} catch(e) {console.log(e);}
});
*/
console.log("Time now is: " + moment(new Date()).format("MMM Do YYYY, h:mm:ss a"));
/*
app.use('/Admin/UserData', function(req, res) {
//TODO: Return a table of user data. This is a hidden function, and since the data is not very sensitive we won't bother with password protection or ssl.
var body = "<html><body><table><thead><tr><th style='padding: 0 20px 0 0'>Password</th><th style='padding: 0 20px 0 20px'>Page Request Count</th><th style='padding: 0 20px 0 20px'>First Login</th><th style='padding: 0 0 0 20px'>Last Login</th></tr></thead><tbody>";
for(var index = 0; index < pwdData.length; index++) {
body += "<tr>";
body += "<td>" + pwdData[index].pwd + "</td>";
body += "<td style='text-align: center'>" + (pwdData[index].accessCount ? pwdData[index].accessCount : 0) + "</td>";
body += "<td style='padding: 0 20px 0 20px'>" + (pwdData[index].firstLogin ? (moment(pwdData[index].firstLogin).format("MMM Do YYYY, h:mm:ss a") + " (" + moment(pwdData[index].firstLogin).fromNow() + ")") : "") + "</td>";
body += "<td style='padding: 0 20px 0 20px'>" + (pwdData[index].lastLogin ? (moment(pwdData[index].lastLogin).format("MMM Do YYYY, h:mm:ss a") + " (" + moment(pwdData[index].lastLogin).fromNow() + ")") : "") + "</td>";
body += "</tr>";
}
body += "</tbody></table></body></html>";
res.send(body);
});
*/
//Handle the root being requested, and the search engine requesting a static page with content.
app.use('/', function(req, res) {
try {
//Note: This is for search engines. It bypasses the password, which is fine since that is mostly a marketing gimmic to make users feel that they have some special access priviliges.
if(typeof(req.query._escaped_fragment_) !== "undefined") {
//The DIY method which is somewhat brittle since it relies on <!--CONTENT--> existing in the index.html file, and it replaces that with the contents of the passed parameter (what is after the #!) for the content html which is inserted into the index.html in place of <!--CONTENT-->.
fs.readFile(rootPath + '/index.html', {encoding: "UTF8"}, function(err, indexContent) {
if(!err) {
var file = rootPath + '/' + req.query._escaped_fragment_ + '.html';
fs.readFile(file, {encoding: "UTF8"}, function(err, content) {
if(!err) {
//Non-regex method.//
if(content.indexOf("<runonce>") != -1 && content.indexOf("</runonce>") != -1) {
content = content.substr(0, content.indexOf("<runonce>")) + content.substr(content.indexOf("</runonce>") + 10, -1);
}
//Doesn't work? Not sure why. Works in the regex test tools.//
//content = content.replace(/<runonce>(.|\n)*?<\x2frunonce>/, " ");
//Doesn't work? Based on the regex failure above, I think that replace is failing.//
var html = indexContent.replace(/<!--CONTENT-->/g, content);
//console.log(html);
res.send(html);
}
else console.log("Error reading the content file '" + file + "'. " + err);
});
}
else console.log("Error reading the index.html file. " + err);
});
/* Does not work! Would be nice, but Phantom doesn't work well with Node.js. Could try using jsdom/io.js or could use prerenderer-node which is a server that runs in parallel with the web server and builds the html as the client would, which is then returned.
phantom.create(function(err, ph) {
if(!err) {
return ph.createPage(function(err, page) {
return page.open(req.protocol + "://" + req.hostname + ':' + req.app.get('port') + req.path + "#!" + req.query._escaped_fragment_, function(status) {
return page.evaluate((function() {
return document.getElementsByTagName('html')[0].innerHTML;
}), function(err, result) {
res.send(result);
return ph.exit();
});
});
});
}
else console.log("Error in Phantom.create: " + err);
});
*/
}
else {
res.sendFile("index.html", {root: rootPath});
}
} catch(e) {console.log(e);}
});
//Schedule a task every 10 minutes to check the email failure log and re-attempt sending.//
/* TODO
setInterval(function() {
//How to remove things from the file without worrying about synchronization between those threads adding to the file?
fs.
}, 600000);
*/
// catch 404 and forward to error handler
app.use(function(req, res, next) {
try {
var err = new Error('Not Found');
err.status = 404;
next(err);
} catch(e) {console.log(e);}
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, nex) {
try {
res.status(err.status || 500);
res.render('error.ejs', {
message: err.message,
error: err
});
} catch(e) {console.log(e);}
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
try {
res.status(err.status || 500);
res.render('error.ejs', {
message: err.message,
error: {}
});
} catch(e) {console.log(e);}
});
//console.log(app._router);
module.exports = app;

View File

@@ -8,12 +8,13 @@ module.exports = function(sequelize) {
if(count == 0) {
var basicJarIds = [];
models.User.create({login: 'wcrisman', password: models.User.generateHash('landFJ40'), admin: true});
models.Venue.create({name: 'Boonville'});
models.Venue.create({name: 'Clement St Farmers Market in SF'});
models.Venue.create({name: 'Ukiah Farmers Market'});
models.Venue.create({name: 'Mendocino Farmers Market'});
models.Venue.create({name: 'Ft Bragg Farmers Market'});
models.Venue.create({name: 'Healdsburg Farmers Market'});
Promise.each([
models.Measure.create({name: 'Jar 4oz', postfix: '4oz'}),

View File

@@ -94,7 +94,7 @@ module.exports = function(app, rootPath, passport, smtpTransport, sequelize) {
});
}
else {
console.log("Looking for index.ejs in " + adminPath);
//console.log("Looking for index.ejs in " + adminPath);
//res.render("index.ejs", {root: adminPath});
res.render(path.join(adminPath, req.baseUrl, "index"));
}
@@ -182,6 +182,26 @@ module.exports = function(app, rootPath, passport, smtpTransport, sequelize) {
});
});
app.get('/admin/user-data', isLoggedIn, function(req, res) {
try {
if(req.user.admin) {
sequelize.models.User.findAll().then(function(values) {
res.json(values);
});
}
else {
}
}
catch(e) {console.log(e);}
});
app.post('/admin/createUser', isLoggedIn, function(req, res) {
try {
res.json({status: 'success'});
} catch(e) {console.log(e);}
});
app.get('/admin/getCategories', isLoggedIn, function(req, res) {
sequelize.models.Category.findAll({attributes: ['id', 'name', 'visible'], order: [['name', 'DESC'], ['visible', 'DESC']]}).then(function(values) {
res.json(values);

92
bin/www
View File

@@ -1,92 +0,0 @@
//NOT USED!!!
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('payback:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '4480');
app.set('port', port);
console.log("Listening on port " + port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

View File

@@ -5,6 +5,12 @@ module.exports = {
var DataTypes = Sequelize; //Allow for more cut and paste :)
return query.createTable('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
login: {
type: DataTypes.STRING
},

View File

@@ -5,6 +5,12 @@ var bcrypt = require('bcrypt-nodejs');
module.exports = function(sequelize, DataTypes) {
//The id field is auto added and made primary key.
return sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
login: {
type: DataTypes.STRING
},
@@ -15,17 +21,22 @@ module.exports = function(sequelize, DataTypes) {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
}
}, {
indexes: [
{
unique: true,
fields: ['login']
}
]
}, {
],
freezeTableName: true, // Model tableName will be the same as the model name
//paranoid: true, //Keep deleted data but flag it as deleted
comment: "A system user authorized to access and manipulate the application data.",
classMethods: {
generateHash: function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
}
},
instanceMethods: {
generateHash: function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);

View File

@@ -3,7 +3,10 @@
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node server.js"
"1. start": "node server.js",
"3. update-db": "sequelize db:migrate",
"4. create-db-migration": "sequelize migration:create",
"2. install": "npm install"
},
"dependencies": {
"bcrypt-nodejs": "^0.0.3",

View File

@@ -1,3 +1,13 @@
/*!
* Bootstrap v3.3.5 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*!
* Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=74bddeade5026a07eb7f668f15f1b64a)
* Config saved to config.json and https://gist.github.com/74bddeade5026a07eb7f668f15f1b64a
*/
/*!
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
@@ -9,9 +19,9 @@
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
}
.btn-default:active,
.btn-primary:active,
@@ -25,8 +35,8 @@
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.btn-default.disabled,
.btn-primary.disabled,
@@ -62,15 +72,15 @@ fieldset[disabled] .btn-danger {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
text-shadow: 0 1px 0 #fff;
border-color: #ccc;
}
.btn-default:hover,
@@ -311,41 +321,41 @@ fieldset[disabled] .btn-danger.active {
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-color: #e8e8e8;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #2e6da4;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-color: #2e6da4;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8));
background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .active > a {
@@ -353,23 +363,23 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222222));
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
}
.navbar-inverse .navbar-nav > .open > a,
@@ -378,14 +388,14 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.navbar-static-top,
.navbar-fixed-top,
@@ -401,22 +411,22 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
}
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
border-color: #b2dba1;
}
.alert-info {
@@ -424,8 +434,8 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
border-color: #9acfea;
}
.alert-warning {
@@ -433,8 +443,8 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
border-color: #f5e79e;
}
.alert-danger {
@@ -442,8 +452,8 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
border-color: #dca7a7;
}
.progress {
@@ -451,58 +461,58 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
}
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
}
.list-group-item.active,
.list-group-item.active:hover,
@@ -512,8 +522,8 @@ fieldset[disabled] .btn-danger.active {
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
border-color: #2b669a;
}
.list-group-item.active .badge,
@@ -522,66 +532,65 @@ fieldset[disabled] .btn-danger.active {
text-shadow: none;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -19,9 +19,9 @@
<link rel="stylesheet" href="main.css" type="text/css"/>
<link rel="stylesheet" href="awesomplete.css" type="text/css"/>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="/css/fancytree/skin-win7/ui.fancytree.min.css" type="text/css">
<link rel="stylesheet" href="/css/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/css/jquery-ui-1.11.4/jquery-ui.min.css">
<link rel="stylesheet" href="/admin/css/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/admin/css/jquery-ui-1.11.4/jquery-ui.min.css">
<script type="text/javascript" language="JavaScript" src="js/jquery-1.11.3.min.js"></script>
<script type="text/javascript" language="JavaScript" src="js/jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript" language="JavaScript" src="js/jquery.history.js"></script>
@@ -35,7 +35,8 @@
<script type="text/javascript" language="JavaScript" src="js/awesomplete.min.js"></script>
<script type="text/javascript" language="JavaScript" src="js/jquery-ui-1.11.4.min.js"></script>
<script type="text/javascript" language="JavaScript" src="js/jquery.fancytree-all.min.js"></script>
<script type="text/javascript" language="JavaScript" src="js/bootstrap.min.js""></script>
<script type="text/javascript" language="JavaScript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" language="JavaScript" src="js/LinkedTable.js"></script>
<script type="text/javascript" language="JavaScript">
function check(x) {
@@ -50,8 +51,8 @@
<div id="menu"><!-- Note: Comment out spacing between the elements since the browser will interpret the spaces as characters to be displayed.
--><a href="#!/dataEntry">Data Entry</a><!--
--><a href="#!/dataEditors">Edit</a><!--
--><a href="#!/animals">??</a><!--
--><a href="/logout">Log Out</a><!--
--><a href="#!/users">Manage Users</a><!--
--><a style="position: absolute; right: 0px;" href="/logout">Log Out</a><!--
--></div>
<div id="menuBackground"></div>
<div id="head">

View File

@@ -1,13 +1,16 @@
/*!
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under the MIT license
* Bootstrap v3.3.5 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*!
* Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=74bddeade5026a07eb7f668f15f1b64a)
* Config saved to config.json and https://gist.github.com/74bddeade5026a07eb7f668f15f1b64a
*/
if (typeof jQuery === 'undefined') {
throw new Error('Bootstrap\'s JavaScript requires jQuery')
}
+function ($) {
'use strict';
var version = $.fn.jquery.split(' ')[0].split('.')
@@ -16,66 +19,6 @@ if (typeof jQuery === 'undefined') {
}
}(jQuery);
/* ========================================================================
* Bootstrap: transition.js v3.3.6
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false
var $el = this
$(this).one('bsTransitionEnd', function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
$(function () {
$.support.transition = transitionEnd()
if (!$.support.transition) return
$.event.special.bsTransitionEnd = {
bindType: $.support.transition.end,
delegateType: $.support.transition.end,
handle: function (e) {
if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
}
}
})
}(jQuery);
/* ========================================================================
* Bootstrap: alert.js v3.3.6
* http://getbootstrap.com/javascript/#alerts
@@ -530,218 +473,6 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: collapse.js v3.3.6
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// COLLAPSE PUBLIC CLASS DEFINITION
// ================================
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
this.transitioning = null
if (this.options.parent) {
this.$parent = this.getParent()
} else {
this.addAriaAndCollapsedClass(this.$element, this.$trigger)
}
if (this.options.toggle) this.toggle()
}
Collapse.VERSION = '3.3.6'
Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = {
toggle: true
}
Collapse.prototype.dimension = function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
Collapse.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('in')) return
var activesData
var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
if (actives && actives.length) {
activesData = actives.data('bs.collapse')
if (activesData && activesData.transitioning) return
}
var startEvent = $.Event('show.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
if (actives && actives.length) {
Plugin.call(actives, 'hide')
activesData || actives.data('bs.collapse', null)
}
var dimension = this.dimension()
this.$element
.removeClass('collapse')
.addClass('collapsing')[dimension](0)
.attr('aria-expanded', true)
this.$trigger
.removeClass('collapsed')
.attr('aria-expanded', true)
this.transitioning = 1
var complete = function () {
this.$element
.removeClass('collapsing')
.addClass('collapse in')[dimension]('')
this.transitioning = 0
this.$element
.trigger('shown.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
var scrollSize = $.camelCase(['scroll', dimension].join('-'))
this.$element
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
if (this.transitioning || !this.$element.hasClass('in')) return
var startEvent = $.Event('hide.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var dimension = this.dimension()
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')
.removeClass('collapse in')
.attr('aria-expanded', false)
this.$trigger
.addClass('collapsed')
.attr('aria-expanded', false)
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
.removeClass('collapsing')
.addClass('collapse')
.trigger('hidden.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
this.$element
[dimension](0)
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
Collapse.prototype.getParent = function () {
return $(this.options.parent)
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
.each($.proxy(function (i, element) {
var $element = $(element)
this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
}, this))
.end()
}
Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
var isOpen = $element.hasClass('in')
$element.attr('aria-expanded', isOpen)
$trigger
.toggleClass('collapsed', !isOpen)
.attr('aria-expanded', isOpen)
}
function getTargetFromTrigger($trigger) {
var href
var target = $trigger.attr('data-target')
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
return $(target)
}
// COLLAPSE PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.collapse
$.fn.collapse = Plugin
$.fn.collapse.Constructor = Collapse
// COLLAPSE NO CONFLICT
// ====================
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
// COLLAPSE DATA-API
// =================
$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
var $this = $(this)
if (!$this.attr('data-target')) e.preventDefault()
var $target = getTargetFromTrigger($this)
var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $this.data()
Plugin.call($target, option)
})
}(jQuery);
/* ========================================================================
* Bootstrap: dropdown.js v3.3.6
* http://getbootstrap.com/javascript/#dropdowns
@@ -1870,179 +1601,6 @@ if (typeof jQuery === 'undefined') {
}(jQuery);
/* ========================================================================
* Bootstrap: scrollspy.js v3.3.6
* http://getbootstrap.com/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// SCROLLSPY CLASS DEFINITION
// ==========================
function ScrollSpy(element, options) {
this.$body = $(document.body)
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
this.selector = (this.options.target || '') + ' .nav li > a'
this.offsets = []
this.targets = []
this.activeTarget = null
this.scrollHeight = 0
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
this.refresh()
this.process()
}
ScrollSpy.VERSION = '3.3.6'
ScrollSpy.DEFAULTS = {
offset: 10
}
ScrollSpy.prototype.getScrollHeight = function () {
return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
}
ScrollSpy.prototype.refresh = function () {
var that = this
var offsetMethod = 'offset'
var offsetBase = 0
this.offsets = []
this.targets = []
this.scrollHeight = this.getScrollHeight()
if (!$.isWindow(this.$scrollElement[0])) {
offsetMethod = 'position'
offsetBase = this.$scrollElement.scrollTop()
}
this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
var href = $el.data('target') || $el.attr('href')
var $href = /^#./.test(href) && $(href)
return ($href
&& $href.length
&& $href.is(':visible')
&& [[$href[offsetMethod]().top + offsetBase, href]]) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
that.offsets.push(this[0])
that.targets.push(this[1])
})
}
ScrollSpy.prototype.process = function () {
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
var scrollHeight = this.getScrollHeight()
var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
var offsets = this.offsets
var targets = this.targets
var activeTarget = this.activeTarget
var i
if (this.scrollHeight != scrollHeight) {
this.refresh()
}
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
}
if (activeTarget && scrollTop < offsets[0]) {
this.activeTarget = null
return this.clear()
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
&& this.activate(targets[i])
}
}
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
this.clear()
var selector = this.selector +
'[data-target="' + target + '"],' +
this.selector + '[href="' + target + '"]'
var active = $(selector)
.parents('li')
.addClass('active')
if (active.parent('.dropdown-menu').length) {
active = active
.closest('li.dropdown')
.addClass('active')
}
active.trigger('activate.bs.scrollspy')
}
ScrollSpy.prototype.clear = function () {
$(this.selector)
.parentsUntil(this.options.target, '.active')
.removeClass('active')
}
// SCROLLSPY PLUGIN DEFINITION
// ===========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.scrollspy
$.fn.scrollspy = Plugin
$.fn.scrollspy.Constructor = ScrollSpy
// SCROLLSPY NO CONFLICT
// =====================
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
// SCROLLSPY DATA-API
// ==================
$(window).on('load.bs.scrollspy.data-api', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
Plugin.call($spy, $spy.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: tab.js v3.3.6
* http://getbootstrap.com/javascript/#tabs
@@ -2361,3 +1919,448 @@ if (typeof jQuery === 'undefined') {
})
}(jQuery);
/* ========================================================================
* Bootstrap: collapse.js v3.3.6
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// COLLAPSE PUBLIC CLASS DEFINITION
// ================================
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
this.transitioning = null
if (this.options.parent) {
this.$parent = this.getParent()
} else {
this.addAriaAndCollapsedClass(this.$element, this.$trigger)
}
if (this.options.toggle) this.toggle()
}
Collapse.VERSION = '3.3.6'
Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = {
toggle: true
}
Collapse.prototype.dimension = function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
Collapse.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('in')) return
var activesData
var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
if (actives && actives.length) {
activesData = actives.data('bs.collapse')
if (activesData && activesData.transitioning) return
}
var startEvent = $.Event('show.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
if (actives && actives.length) {
Plugin.call(actives, 'hide')
activesData || actives.data('bs.collapse', null)
}
var dimension = this.dimension()
this.$element
.removeClass('collapse')
.addClass('collapsing')[dimension](0)
.attr('aria-expanded', true)
this.$trigger
.removeClass('collapsed')
.attr('aria-expanded', true)
this.transitioning = 1
var complete = function () {
this.$element
.removeClass('collapsing')
.addClass('collapse in')[dimension]('')
this.transitioning = 0
this.$element
.trigger('shown.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
var scrollSize = $.camelCase(['scroll', dimension].join('-'))
this.$element
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
if (this.transitioning || !this.$element.hasClass('in')) return
var startEvent = $.Event('hide.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var dimension = this.dimension()
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')
.removeClass('collapse in')
.attr('aria-expanded', false)
this.$trigger
.addClass('collapsed')
.attr('aria-expanded', false)
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
.removeClass('collapsing')
.addClass('collapse')
.trigger('hidden.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
this.$element
[dimension](0)
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
Collapse.prototype.getParent = function () {
return $(this.options.parent)
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
.each($.proxy(function (i, element) {
var $element = $(element)
this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
}, this))
.end()
}
Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
var isOpen = $element.hasClass('in')
$element.attr('aria-expanded', isOpen)
$trigger
.toggleClass('collapsed', !isOpen)
.attr('aria-expanded', isOpen)
}
function getTargetFromTrigger($trigger) {
var href
var target = $trigger.attr('data-target')
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
return $(target)
}
// COLLAPSE PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.collapse
$.fn.collapse = Plugin
$.fn.collapse.Constructor = Collapse
// COLLAPSE NO CONFLICT
// ====================
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
// COLLAPSE DATA-API
// =================
$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
var $this = $(this)
if (!$this.attr('data-target')) e.preventDefault()
var $target = getTargetFromTrigger($this)
var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $this.data()
Plugin.call($target, option)
})
}(jQuery);
/* ========================================================================
* Bootstrap: scrollspy.js v3.3.6
* http://getbootstrap.com/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// SCROLLSPY CLASS DEFINITION
// ==========================
function ScrollSpy(element, options) {
this.$body = $(document.body)
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
this.selector = (this.options.target || '') + ' .nav li > a'
this.offsets = []
this.targets = []
this.activeTarget = null
this.scrollHeight = 0
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
this.refresh()
this.process()
}
ScrollSpy.VERSION = '3.3.6'
ScrollSpy.DEFAULTS = {
offset: 10
}
ScrollSpy.prototype.getScrollHeight = function () {
return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
}
ScrollSpy.prototype.refresh = function () {
var that = this
var offsetMethod = 'offset'
var offsetBase = 0
this.offsets = []
this.targets = []
this.scrollHeight = this.getScrollHeight()
if (!$.isWindow(this.$scrollElement[0])) {
offsetMethod = 'position'
offsetBase = this.$scrollElement.scrollTop()
}
this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
var href = $el.data('target') || $el.attr('href')
var $href = /^#./.test(href) && $(href)
return ($href
&& $href.length
&& $href.is(':visible')
&& [[$href[offsetMethod]().top + offsetBase, href]]) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
that.offsets.push(this[0])
that.targets.push(this[1])
})
}
ScrollSpy.prototype.process = function () {
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
var scrollHeight = this.getScrollHeight()
var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
var offsets = this.offsets
var targets = this.targets
var activeTarget = this.activeTarget
var i
if (this.scrollHeight != scrollHeight) {
this.refresh()
}
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
}
if (activeTarget && scrollTop < offsets[0]) {
this.activeTarget = null
return this.clear()
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
&& this.activate(targets[i])
}
}
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
this.clear()
var selector = this.selector +
'[data-target="' + target + '"],' +
this.selector + '[href="' + target + '"]'
var active = $(selector)
.parents('li')
.addClass('active')
if (active.parent('.dropdown-menu').length) {
active = active
.closest('li.dropdown')
.addClass('active')
}
active.trigger('activate.bs.scrollspy')
}
ScrollSpy.prototype.clear = function () {
$(this.selector)
.parentsUntil(this.options.target, '.active')
.removeClass('active')
}
// SCROLLSPY PLUGIN DEFINITION
// ===========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.scrollspy
$.fn.scrollspy = Plugin
$.fn.scrollspy.Constructor = ScrollSpy
// SCROLLSPY NO CONFLICT
// =====================
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
// SCROLLSPY DATA-API
// ==================
$(window).on('load.bs.scrollspy.data-api', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
Plugin.call($spy, $spy.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: transition.js v3.3.6
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false
var $el = this
$(this).one('bsTransitionEnd', function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
$(function () {
$.support.transition = transitionEnd()
if (!$.support.transition) return
$.event.special.bsTransitionEnd = {
bindType: $.support.transition.end,
delegateType: $.support.transition.end,
handle: function (e) {
if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
}
}
})
}(jQuery);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,80 @@
"use strict";
var LinkedTable;
+function($) {
LinkedTable = function(element, options) {
this.$element = $(element);
this.options = $.extend({}, LinkedTable.DEFAULTS, options);
this.clickHandler = function(event) {
$(this).addClass('highlight').siblings().removeClass('highlight');
};
};
LinkedTable.DEFAULTS = {
url: '', //The absolute or relative path to use to query the data. Server is expected to respond with a JSON array of objects.
attr: 'data-key-name',
selection: 'row' //Currently only row is supported.
};
//TODO
LinkedTable.prototype.myMethod = function() {
};
//A function that will clean and rebuild the table displaying all the users.
LinkedTable.prototype.refresh = function() {
var table = this.$element;
var thead = table.find("thead tr");
var tbody = table.find("tbody");
var selection = this.options.selection;
var attr = this.options.attr;
var clickHandler = this.clickHandler;
if(thead.length == 0) {
return;
}
//Empty or Create the table body.
if(tbody.length != 0) {
//Remove the row selection handler.
if(selection == 'row') this.$element.off('click', 'tbody tr', clickHandler);
//Empty the table of data.
tbody.empty();
}
else {
tbody = $("<tbody></tbody>");
tbody.appendTo(table);
}
$.getJSON("user-data", function(data) {
var headers = thead.children();
var attributes = [];
//Read the table headers to get the data object keys.
for(var headerIndex = 0; headerIndex < headers.length; headerIndex++) {
var nextHeader = headers[headerIndex];
attributes[headerIndex] = $(nextHeader).attr(attr);
}
//Add the table data.
for(var dataIndex = 0; dataIndex < data.length; dataIndex++) {
var rowData = data[dataIndex];
var row = $("<tr></tr>");
row.appendTo(tbody);
for(var attributeIndex = 0; attributeIndex < attributes.length; attributeIndex++) {
var attribute = attributes[attributeIndex];
var cellData = rowData[attribute];
row.append("<td>" + cellData + "</td>");
}
}
//Setup the row selection handler.
if(selection == 'row') table.on('click', 'tbody tr', clickHandler);
});
}
}(jQuery);

View File

@@ -49,6 +49,9 @@ body {
background: #F6F6F6;*/
background: #fdfdfd;
}
#menu {
width: 100%;
}
/* Small Devices (phones) */
@media (max-width: 549px) {
#head {
@@ -494,3 +497,6 @@ sub {
.headerIcon {
width: 30px;
}
#users .highlight {
background-color: #ffe184 !important;
}

View File

@@ -54,6 +54,10 @@ body {
background: #FDFDFD;
}
#menu {
width: 100%;
}
/* Small Devices (phones) */
@media(max-width: 549px) {
#head {
@@ -100,7 +104,6 @@ body {
color: black;
border-bottom: 1px solid red;
}
}
/* Large(r) Devices (tablets and full computers) */
@@ -464,3 +467,4 @@ sup, sub {
@require "home"
@require "editor"
@require "users"

0
public/admin/users.css Normal file
View File

67
public/admin/users.html Normal file
View File

@@ -0,0 +1,67 @@
<div id="users" class="page">
<div class="col-sm-12 col-sm-offset-0">
<h1><span class="fa fa-users"></span> Manage Users</h1>
<div class="col-sm-6">
<div class="dt-buttons btn-group">
<a id="createButton" class="btn btn-default buttons-create" tabindex="0" href="javaScript:void(0);"><span>New</span></a>
<a class="btn btn-default buttons-selected buttons-edit" tabindex="0" href="javaScript:void(0);"><span>Edit</span></a>
<a class="btn btn-default buttons-selected buttons-remove" tabindex="0" href="javaScript:void(0);"><span>Delete</span></a>
</div>
</div>
<table id="user-table" class="table table-striped table-hover">
<thead>
<tr>
<th data-key-name="login">Name</th>
<th data-key-name="admin">Admin</th>
</tr>
</thead>
</table>
<div id="createUserDialog" class="modal fade" role="dialog">
<div class="modal-dialog">
<!--<form action="/admin/createUser" method="post">-->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Create User</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>Login</label>
<input type="text" class="form-control" name="login" id="loginDialogLogin">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" id="loginDialogPassword">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning btn-md" id="createUserDialogButton">Create</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<!--</form>-->
</div>
</div>
<script language="JavaScript" type="text/javascript">
var userTable = new LinkedTable($('#user-table'), {url: "user-data", attr: "data-key-name", selection: "row"});
//Call the refresh user table function once initially.
userTable.refresh();
$("#createButton").on("click", function(event) {
$("#createUserDialog").modal();
});
$("#createUserDialogButton").on("click", function(event) {
$.post("createUser", {login: $("#loginDialogLogin"), password: $("#loginDialogPassword")}, function(data) {
if(data.result == "success") {
}
else {
alert(data.result);
}
}, "json");
})
</script>
</div>
</div>

5
public/admin/users.styl Normal file
View File

@@ -0,0 +1,5 @@
#users {
.highlight {
background-color: #ffe184 !important;
}
}

View File

@@ -19,11 +19,13 @@
<p>We often have a small herd of pregnant cows grazing down the grass around the farm's hills, and we have one cow of our own in the front yard that keeps Cica, the yak, company. We sell beef from the farm, sourced from our neighbor and butchered locally</p>
</div>
-->
<!--
<div class="columnContent" onclick="window.location.hash='#!/yaks'">
<h2>Yaks</h2>
<img src="images/AnimalsYaks_v1.jpg" alt="" border="0" align="left"/>
<p>We have our own herd of semi-wild yaks that attract the attention of visitors, and we have Cica, a rather human friendly yak that hangs out in our front yard. Stop by and hang out with the yaks, and try your hand at talking 'yak'.</p>
</div>
-->
<div class="columnContent" onclick="window.location.hash='#!/aquaponics'">
<h2>Fish</h2>
<img src="images/Animals_Fish_v1.jpg" alt="" border="0" align="left"/>

View File

@@ -8,7 +8,7 @@
<div style="margin: 0 auto; width:600px;"><img src='images/Aquaponic1_v1.jpg' class="shadow" style="width:580px; height:326px;" style="float: none; margin: 0;"/></div>
<div style="margin: 0 auto; width: 600px; font-family: 'trebuchet ms', geneva; font-size: .9em; font-weight: 800; text-align: center;">For more aquaponic information, please see <a href="https://blog.petitteton.com/tag/aquaponics/" target="_blank">the aquaponic section of our blog.</a></div>
<p>
Wynne gives classes in aquaponics for kids ages 9 and up, and adults of all varieties. We also offer tours and consulting to help you avoid many of the expensive mistakes as you design your own aquaponic system. Tours are $30 for up to 3 people and $10 per person to a maximum of 6 people. To arrange for classes, tours, or consulting, please <a href="#!/visiting">call the farm <b>707.684.4146</b> or email</a>. If you need to contact Wynne directly (for technical questions) you may email <a href="mailto:wynne@petitteton.com">wynne@petitteton.com</a> or try calling <b>707.684.4148</b> if it is urgent.
<!--Wynne gives classes in aquaponics for kids ages 9 and up, and adults of all varieties. We also offer --> We offer tours and consulting to help you avoid many of the expensive mistakes as you design your own aquaponic system. Tours are $30 for up to 3 people and $10 per person to a maximum of 6 people. To arrange for classes, tours, or consulting, please <a href="#!/visiting">call the farm <b>707.684.4146</b> or email</a>. If you need to contact Wynne directly (for technical questions) you may email <a href="mailto:wynne@petitteton.com">wynne@petitteton.com</a> or try calling <b>707.684.4148</b> if it is urgent.
</p>
</div>
</div>

View File

@@ -7,11 +7,13 @@
<img src="images/Services_WeddingFlowers_v1.jpg" alt="" border="0" align="left"/>
<p>Have us grow flowers specifically for your wedding.</p>
</div>
<!--
<div class="columnContent" onclick="window.location.hash='#!/aquaponics'">
<h2>Aquaponic Classes</h2>
<img src="images/Services_Aquaponics_v1.jpg" alt="" border="0" align="left"/>
<p>Interested in aquaponics at home? We offer customized courses on aquaponics for kids and adults.</p>
</div>
-->
<!--
<div class="columnContent" onclick="window.location.hash='#!/farm-tours'">
<h2>Farm Tours</h2>

View File

@@ -8,6 +8,7 @@ var flash = require('connect-flash');
var path = require('path');
var ejsPath = path.join(__dirname, 'public');
var rootPath = path.join(__dirname, 'public');
var favicon = require('serve-favicon');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
@@ -16,7 +17,6 @@ var session = require('express-session');
var FileStore = require('session-file-store')(session);
var moment = require('moment');
var favicon = require('serve-favicon');
var nodeMailer = require('nodemailer');
//var configDB = require('./config/database.js');
var config = require('./config');
@@ -27,7 +27,7 @@ var models = require("./models");
var smtpTransport = nodeMailer.createTransport({host: config.smtpHost, port: config.smtpPort, secure: true, ignoreTLS: false, requiresAuth: true, auth: {user: config.smtpUser, pass: config.smtpPassword}});
//Setup our passport configuration passing the user model.
require('./config/passport')(passport, models.User); // pass passport for configuration
require('./app/passport')(passport, models.User); // pass passport for configuration
//Serve the fav icon before any logging.
app.use(favicon(__dirname + '/public/images/Chicken.ico'));