Updated from upstream

This commit is contained in:
Geoff Storbeck
2015-04-04 12:16:00 -04:00
62 changed files with 4005 additions and 3172 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
root = true
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[package.json]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false

83
app.js
View File

@ -2,11 +2,20 @@ if (process.env.NODE_ENV !== 'development') {
require('newrelic');
}
require('dotenv').load();
/**
* Module dependencies.
*/
// handle uncaught exceptions. Forever will restart process on shutdown
process.on('uncaughtException', function (err) {
console.error(
(new Date()).toUTCString() + ' uncaughtException:',
err.message
);
console.error(err.stack);
/* eslint-disable no-process-exit */
process.exit(1);
/* eslint-enable no-process-exit */
});
var express = require('express'),
//accepts = require('accepts'),
cookieParser = require('cookie-parser'),
compress = require('compression'),
session = require('express-session'),
@ -27,17 +36,17 @@ var express = require('express'),
* Controllers (route handlers).
*/
homeController = require('./controllers/home'),
challengesController = require('./controllers/challenges'),
resourcesController = require('./controllers/resources'),
userController = require('./controllers/user'),
contactController = require('./controllers/contact'),
nonprofitController = require('./controllers/nonprofits'),
bonfireController = require('./controllers/bonfire'),
coursewareController = require('./controllers/courseware'),
/**
* Stories
*/
storyController = require('./controllers/story');
storyController = require('./controllers/story'),
/**
* API keys and Passport configuration.
@ -96,7 +105,7 @@ app.use(session({
secret: secrets.sessionSecret,
store: new MongoStore({
url: secrets.db,
'auto_reconnect': true
'autoReconnect': true
})
}));
app.use(passport.initialize());
@ -204,7 +213,9 @@ app.use(function (req, res, next) {
app.use(function (req, res, next) {
// Remember original destination before login.
var path = req.path.split('/')[1];
if (/auth|login|logout|signup|fonts|favicon/i.test(path)) {
if (/auth|login|logout|signin|signup|fonts|favicon/i.test(path)) {
return next();
} else if (/\/stories\/comments\/\w+/i.test(req.path)) {
return next();
}
req.session.returnTo = req.path;
@ -264,6 +275,18 @@ app.post('/email-signup', userController.postEmailSignup);
app.post('/email-signin', userController.postSignin);
app.get('/nonprofits', contactController.getNonprofitsForm);
app.post('/nonprofits', contactController.postNonprofitsForm);
app.get('/nonprofits/home', nonprofitController.nonprofitsHome);
app.get('/nonprofits/are-you-with-a-registered-nonprofit', nonprofitController.areYouWithARegisteredNonprofit);
app.get('/nonprofits/are-there-people-that-are-already-benefiting-from-your-services', nonprofitController.areTherePeopleThatAreAlreadyBenefitingFromYourServices);
app.get('/nonprofits/in-exchange-we-ask', nonprofitController.inExchangeWeAsk);
app.get('/nonprofits/ok-with-javascript', nonprofitController.okWithJavaScript);
app.get('/nonprofits/how-can-free-code-camp-help-you', nonprofitController.howCanFreeCodeCampHelpYou);
app.get('/nonprofits/what-does-your-nonprofit-do', nonprofitController.whatDoesYourNonprofitDo);
app.get('/nonprofits/link-us-to-your-website', nonprofitController.linkUsToYourWebsite);
app.get('/nonprofits/tell-us-your-name', nonprofitController.tellUsYourName);
app.get('/nonprofits/tell-us-your-email', nonprofitController.tellUsYourEmail);
app.get('/nonprofits/your-nonprofit-project-application-has-been-submitted', nonprofitController.yourNonprofitProjectApplicationHasBeenSubmitted);
app.get('/nonprofits/other-solutions', nonprofitController.otherSolutions);
app.get(
'/done-with-first-100-hours',
@ -417,6 +440,8 @@ app.get(
coursewareController.returnIndividualCourseware
);
app.post('/completed-courseware/', coursewareController.completedCourseware);
app.post('/completed-zipline-or-basejump',
coursewareController.completedZiplineOrBasejump);
// Unique Check API route
app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername);
@ -428,9 +453,6 @@ app.post('/account/password', userController.postUpdatePassword);
app.post('/account/delete', userController.postDeleteAccount);
app.get('/account/unlink/:provider', userController.getOauthUnlink);
app.get('/sitemap.xml', resourcesController.sitemap);
/**
* OAuth sign-in routes.
*/
@ -492,17 +514,54 @@ app.get(
}
);
app.get('/induce-vomiting', function(req, res, next) {
next(new Error('vomiting induced'));
});
// put this route last
app.get(
'/:username',
userController.returnUser
);
/**
* 500 Error Handler.
*/
app.use(errorHandler());
if (process.env.NODE_ENV === 'development') {
app.use(errorHandler({ log: true }));
} else {
// error handling in production
app.use(function(err, req, res, next) {
// respect err.status
if (err.status) {
res.statusCode = err.status;
}
// default status code to 500
if (res.statusCode < 400) {
res.statusCode = 500;
}
// parse res type
var accept = accepts(req);
var type = accept.type('html', 'json', 'text');
var message = 'opps! Something went wrong. Please try again later';
if (type === 'html') {
req.flash('errors', { msg: message });
return res.redirect('/');
// json
} else if (type === 'json') {
res.setHeader('Content-Type', 'application/json');
return res.send({ message: message });
// plain text
} else {
res.setHeader('Content-Type', 'text/plain');
return res.send(message);
}
});
}
/**
* Start Express server.

View File

@ -27,6 +27,7 @@ passport.deserializeUser(function(id, done) {
passport.use(new LocalStrategy({ usernameField: 'email' }, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) return done(null, false, { message: 'Email ' + email + ' not found'});
user.comparePassword(password, function(err, isMatch) {
if (isMatch) {
@ -60,17 +61,19 @@ passport.use(new FacebookStrategy(secrets.facebook, function(req, accessToken, r
User.findOne({ facebook: profile.id }, function(err, existingUser) {
if (existingUser) {
req.flash('errors', { msg: 'There is already a Facebook account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
done(err);
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
user.facebook = profile.id;
user.tokens.push({ kind: 'facebook', accessToken: accessToken });
user.profile.name = user.profile.name || profile.displayName;
user.profile.gender = user.profile.gender || profile._json.gender;
user.profile.picture = user.profile.picture || 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png';
user.save(function(err) {
if (err) { return done(err); }
req.flash('info', { msg: 'Facebook account has been linked.' });
done(err, user);
done(null, user);
});
});
}
@ -81,7 +84,7 @@ passport.use(new FacebookStrategy(secrets.facebook, function(req, accessToken, r
User.findOne({ email: profile._json.email }, function(err, existingEmailUser) {
if (existingEmailUser) {
req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with Facebook manually from Account Settings.' });
done(err);
done();
} else {
var user = new User();
user.email = profile._json.email;
@ -128,9 +131,10 @@ passport.use(new FacebookStrategy(secrets.facebook, function(req, accessToken, r
passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refreshToken, profile, done) {
if (req.user) {
User.findOne({ github: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) {
req.flash('errors', { msg: 'There is already a GitHub account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
done(err);
done();
} else {
User.findById(req.user.id, function(err, user) {
user.github = profile.id;
@ -140,19 +144,22 @@ passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refre
user.profile.location = user.profile.location || profile._json.location;
user.profile.website = user.profile.website || profile._json.blog;
user.save(function(err) {
if (err) { return done(err); }
req.flash('info', { msg: 'GitHub account has been linked.' });
done(err, user);
done(null, user);
});
});
}
});
} else {
User.findOne({ github: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) return done(null, existingUser);
User.findOne({ email: profile._json.email }, function(err, existingEmailUser) {
if (err) { return done(err); }
if (existingEmailUser) {
req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with GitHub manually from Account Settings.' });
done(err);
done(null);
} else {
var user = new User();
user.email = profile._json.email;
@ -163,8 +170,7 @@ passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refre
user.profile.location = profile._json.location;
user.profile.website = profile._json.blog;
user.save(function(err) {
done(err, user);
});
if (err) { return done(err); }
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
@ -186,7 +192,9 @@ passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refre
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
if (err) { return done(err); }
done(null, user);
});
});
}
});
@ -199,9 +207,10 @@ passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refre
passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tokenSecret, profile, done) {
if (req.user) {
User.findOne({ twitter: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) {
req.flash('errors', { msg: 'There is already a Twitter account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
done(err);
done();
} else {
User.findById(req.user.id, function(err, user) {
user.twitter = profile.id;
@ -212,8 +221,9 @@ passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tok
user.profile.picture = user.profile.picture || profile._json.profile_image_url_https.replace('_normal', '');
user.profile.twitterHandle = user.profile.twitterHandle || profile.username.toLowerCase();
user.save(function(err) {
if (err) { return done(err); }
req.flash('info', { msg: 'Twitter account has been linked.' });
done(err, user);
done(null, user);
});
});
}
@ -221,6 +231,7 @@ passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tok
} else {
User.findOne({ twitter: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) return done(null, existingUser);
var user = new User();
user.profile.username = profile.username.toLowerCase();
@ -231,7 +242,8 @@ passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tok
user.profile.picture = profile._json.profile_image_url_https.replace('_normal', '');
user.profile.twitterHandle = user.profile.twitterHandle || profile.username.toLowerCase();
user.save(function(err) {
done(err, user);
if (err) { return done(err); }
done(null, user);
});
});
}
@ -242,30 +254,35 @@ passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tok
passport.use(new GoogleStrategy(secrets.google, function(req, accessToken, refreshToken, profile, done) {
if (req.user) {
User.findOne({ google: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) {
req.flash('errors', { msg: 'There is already a Google account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
done(err);
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
user.google = profile.id;
user.tokens.push({ kind: 'google', accessToken: accessToken });
user.profile.name = user.profile.name || profile.displayName;
user.profile.gender = user.profile.gender || profile._json.gender;
user.profile.picture = user.profile.picture || profile._json.picture;
user.save(function(err) {
if (err) { return done(err); }
req.flash('info', { msg: 'Google account has been linked.' });
done(err, user);
done(null, user);
});
});
}
});
} else {
User.findOne({ google: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) return done(null, existingUser);
User.findOne({ email: profile._json.email }, function(err, existingEmailUser) {
if (err) { return done(err); }
if (existingEmailUser) {
req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with Google manually from Account Settings.' });
done(err);
done();
} else {
var user = new User();
user.email = profile._json.email;
@ -275,8 +292,7 @@ passport.use(new GoogleStrategy(secrets.google, function(req, accessToken, refre
user.profile.gender = profile._json.gender;
user.profile.picture = profile._json.picture;
user.save(function(err) {
done(err, user);
});
if (err) { return done(err); }
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
@ -299,6 +315,8 @@ passport.use(new GoogleStrategy(secrets.google, function(req, accessToken, refre
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
done(null, user);
});
});
}
});
@ -311,11 +329,13 @@ passport.use(new GoogleStrategy(secrets.google, function(req, accessToken, refre
passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, refreshToken, profile, done) {
if (req.user) {
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) {
req.flash('errors', { msg: 'There is already a LinkedIn account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
done(err);
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
user.linkedin = profile.id;
user.tokens.push({ kind: 'linkedin', accessToken: accessToken });
user.profile.name = user.profile.name || profile.displayName;
@ -323,8 +343,9 @@ passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, r
user.profile.picture = user.profile.picture || profile._json.pictureUrl;
user.profile.website = user.profile.website || profile._json.publicProfileUrl;
user.save(function(err) {
if (err) { return done(err); }
req.flash('info', { msg: 'LinkedIn account has been linked.' });
done(err, user);
done(null, user);
});
});
}
@ -333,9 +354,10 @@ passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, r
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
if (existingUser) return done(null, existingUser);
User.findOne({ email: profile._json.emailAddress }, function(err, existingEmailUser) {
if (err) { return done(err); }
if (existingEmailUser) {
req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with LinkedIn manually from Account Settings.' });
done(err);
done();
} else {
var user = new User();
user.linkedin = profile.id;
@ -346,8 +368,7 @@ passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, r
user.profile.picture = profile._json.pictureUrl;
user.profile.website = profile._json.publicProfileUrl;
user.save(function(err) {
done(err, user);
});
if (err) { return done(err); }
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
@ -370,6 +391,8 @@ passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, r
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
done(null, user);
});
});
}
});
@ -380,7 +403,7 @@ passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, r
// Login Required middleware.
exports.isAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) return next();
if (req.isAuthenticated()) { return next(); }
res.redirect('/login');
};

21
controllers/basejumps.js Normal file
View File

@ -0,0 +1,21 @@
var async = require('async'),
User = require('../models/User'),
Challenge = require('./../models/Challenge'),
Bonfire = require('./../models/Bonfire'),
Story = require('./../models/Story'),
Comment = require('./../models/Comment'),
resources = require('./resources.json'),
steps = resources.steps,
secrets = require('./../config/secrets'),
moment = require('moment'),
https = require('https'),
debug = require('debug')('freecc:cntr:resources'),
cheerio = require('cheerio'),
request = require('request'),
R = require('ramda');
nonprofitHome: function nonprofitHome(req, res) {
res.render('nonprofits/home', {
title: 'A guide to our Nonprofit Projects'
});
}

View File

@ -3,17 +3,21 @@ var _ = require('lodash'),
Bonfire = require('./../models/Bonfire'),
User = require('./../models/User'),
resources = require('./resources'),
MDNlinks = require('./../seed_data/bonfireMDNlinks'),
R = require('ramda');
MDNlinks = require('./../seed_data/bonfireMDNlinks');
/**
* Bonfire controller
*/
exports.showAllBonfires = function(req, res) {
var completedBonfires = req.user.completedBonfires.map(function(elem) {
var completedBonfires = [];
if(req.user) {
completedBonfires = req.user.completedBonfires.map(function (elem) {
return elem._id;
});
}
var noDuplicateBonfires = R.uniq(completedBonfires);
var data = {};
data.bonfireList = resources.allBonfireNames();
@ -42,7 +46,7 @@ exports.index = function(req, res) {
});
};
exports.returnNextBonfire = function(req, res) {
exports.returnNextBonfire = function(req, res, next) {
if (!req.user) {
return res.redirect('../bonfires/meet-bonfire');
}
@ -62,7 +66,7 @@ exports.returnNextBonfire = function(req, res) {
var displayedBonfires = Bonfire.find({'_id': uncompletedBonfires[0]});
displayedBonfires.exec(function(err, bonfire) {
if (err) {
next(err);
return next(err);
}
bonfire = bonfire.pop();
if (bonfire === undefined) {
@ -71,7 +75,7 @@ exports.returnNextBonfire = function(req, res) {
});
return res.redirect('../bonfires/meet-bonfire');
}
nameString = bonfire.name.toLowerCase().replace(/\s/g, '-');
var nameString = bonfire.name.toLowerCase().replace(/\s/g, '-');
return res.redirect('../bonfires/' + nameString);
});
};
@ -79,9 +83,9 @@ exports.returnNextBonfire = function(req, res) {
exports.returnIndividualBonfire = function(req, res, next) {
var dashedName = req.params.bonfireName;
bonfireName = dashedName.replace(/\-/g, ' ');
var bonfireName = dashedName.replace(/\-/g, ' ');
Bonfire.find({"name" : new RegExp(bonfireName, 'i')}, function(err, bonfire) {
Bonfire.find({'name': new RegExp(bonfireName, 'i')}, function(err, bonfire) {
if (err) {
next(err);
}
@ -100,7 +104,6 @@ exports.returnIndividualBonfire = function(req, res, next) {
if (dashedNameFull != dashedName) {
return res.redirect('../bonfires/' + dashedNameFull);
}
res.render('bonfire/show', {
completedWith: null,
title: bonfire.name,
@ -112,20 +115,25 @@ exports.returnIndividualBonfire = function(req, res, next) {
tests: bonfire.tests,
challengeSeed: bonfire.challengeSeed,
cc: !!req.user,
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
points: req.user ? req.user.points : undefined,
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
bonfires: bonfire,
bonfireHash: bonfire._id
bonfireHash: bonfire._id,
MDNkeys: bonfire.MDNlinks,
MDNlinks: getMDNlinks(bonfire.MDNlinks)
});
});
};
/**
* Bonfire generator
* Bonfire Generator
* @param req Request Object
* @param res Response Object
* @returns void
*/
exports.returnGenerator = function(req, res) {
res.render('bonfire/generator', {
title: null,
@ -144,7 +152,7 @@ exports.returnGenerator = function(req, res) {
*/
function randomString() {
var chars = "0123456789abcdef";
var chars = '0123456789abcdef';
var string_length = 23;
var randomstring = 'a';
for (var i = 0; i < string_length; i++) {
@ -152,6 +160,23 @@ function randomString() {
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}
/**
* Helper function to populate the MDN links array.
*/
function getMDNlinks(links) {
// takes in an array of links, which are strings
var populatedLinks = [];
// for each key value, push the corresponding link from the MDNlinks object into a new array
links.forEach(function(value, index) {
populatedLinks.push(MDNlinks[value]);
});
return populatedLinks;
};
/**
@ -169,6 +194,7 @@ exports.testBonfire = function(req, res) {
bonfireTests.filter(getRidOfEmpties);
bonfireDescription.filter(getRidOfEmpties);
bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
res.render('bonfire/show', {
completedWith: null,
title: bonfireName,
@ -184,7 +210,7 @@ exports.testBonfire = function(req, res) {
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
bonfires: [],
bonfireHash: "test"
bonfireHash: 'test'
});
};
@ -192,7 +218,7 @@ function getRidOfEmpties(elem) {
if (elem.length > 0) {
return elem;
}
};
}
exports.publicGenerator = function(req, res) {
res.render('bonfire/public-generator');
@ -222,28 +248,29 @@ exports.generateChallenge = function(req, res) {
res.send(response);
};
exports.completedBonfire = function (req, res) {
var isCompletedWith = req.body.bonfireInfo.completedWith || undefined;
var isCompletedDate = Math.round(+new Date() / 1000);
exports.completedBonfire = function (req, res, next) {
var isCompletedWith = req.body.bonfireInfo.completedWith || '';
var isCompletedDate = Math.round(+new Date());
var bonfireHash = req.body.bonfireInfo.bonfireHash;
var isSolution = req.body.bonfireInfo.solution;
if (isCompletedWith) {
var paired = User.find({"profile.username": isCompletedWith.toLowerCase()}).limit(1);
var paired = User.find({'profile.username': isCompletedWith
.toLowerCase()}).limit(1);
paired.exec(function (err, pairedWith) {
if (err) {
return err;
return next(err);
} else {
var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) {
req.user.progressTimestamps.push(Date.now() / 1000 | 0);
req.user.uncompletedBonfires.splice(index, 1)
req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedBonfires.splice(index, 1);
}
pairedWith = pairedWith.pop();
index = pairedWith.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) {
pairedWith.progressTimestamps.push(Date.now() / 1000 | 0);
pairedWith.progressTimestamps.push(Date.now() || 0);
pairedWith.uncompletedBonfires.splice(index, 1);
}
@ -260,22 +287,24 @@ exports.completedBonfire = function (req, res) {
completedWith: pairedWith._id,
completedDate: isCompletedDate,
solution: isSolution
})
});
req.user.save(function (err, user) {
if (err) {
return next(err);
}
pairedWith.save(function (err, paired) {
if (err) {
throw err;
return next(err);
}
if (user && paired) {
res.send(true);
}
})
});
});
}
})
});
} else {
req.user.completedBonfires.push({
_id: bonfireHash,
completedWith: null,
@ -285,17 +314,18 @@ exports.completedBonfire = function (req, res) {
var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) {
req.user.progressTimestamps.push(Date.now() / 1000 | 0);
req.user.uncompletedBonfires.splice(index, 1)
req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedBonfires.splice(index, 1);
}
req.user.save(function (err, user) {
if (err) {
throw err;
return next(err);
}
if (user) {
debug('Saving user');
res.send(true)
res.send(true);
}
});
}

View File

@ -3,16 +3,20 @@ var _ = require('lodash'),
Courseware = require('./../models/Courseware'),
User = require('./../models/User'),
resources = require('./resources'),
R = require('ramda');
R = require('ramda'),
moment = require('moment');
/**
* Courseware controller
*/
exports.showAllCoursewares = function(req, res) {
var completedCoursewares = req.user.completedCoursewares.map(function(elem) {
var completedList = [];
if(req.user) {
completedList = req.user.completedList.map(function (elem) {
return elem._id;
});
}
var noDuplicatedCoursewares = R.uniq(completedCoursewares);
var data = {};
@ -21,7 +25,7 @@ exports.showAllCoursewares = function(req, res) {
res.send(data);
};
exports.returnNextCourseware = function(req, res) {
exports.returnNextCourseware = function(req, res, next) {
if (!req.user) {
return res.redirect('../challenges/learn-how-free-code-camp-works');
}
@ -29,7 +33,8 @@ exports.returnNextCourseware = function(req, res) {
return elem._id;
});
req.user.uncompletedCoursewares = resources.allCoursewareIds().filter(function (elem) {
req.user.uncompletedCoursewares = resources.allCoursewareIds()
.filter(function (elem) {
if (completed.indexOf(elem) === -1) {
return elem;
}
@ -42,13 +47,14 @@ exports.returnNextCourseware = function(req, res) {
var displayedCoursewares = Courseware.find({'_id': uncompletedCoursewares});
displayedCoursewares.exec(function(err, courseware) {
if (err) {
next(err);
return next(err);
}
courseware = courseware.pop();
if (courseware === undefined) {
req.flash('errors', {
msg: "It looks like you've completed all the courses we have available. Good job!"
msg: "It looks like you've completed all the courses we have " +
"available. Good job!"
});
return res.redirect('../challenges/learn-how-free-code-camp-works');
}
@ -60,16 +66,18 @@ exports.returnNextCourseware = function(req, res) {
exports.returnIndividualCourseware = function(req, res, next) {
var dashedName = req.params.coursewareName;
coursewareName = dashedName.replace(/\-/g, ' ');
var coursewareName = dashedName.replace(/\-/g, ' ');
Courseware.find({"name" : new RegExp(coursewareName, 'i')}, function(err, courseware) {
Courseware.find({'name': new RegExp(coursewareName, 'i')},
function(err, courseware) {
if (err) {
next(err);
}
// Handle not found
if (courseware.length < 1) {
req.flash('errors', {
msg: "404: We couldn't find a challenge with that name. Please double check the name."
msg: "404: We couldn't find a challenge with that name. " +
"Please double check the name."
});
return res.redirect('/challenges');
}
@ -91,13 +99,12 @@ exports.returnIndividualCourseware = function(req, res, next) {
details: courseware.description.slice(1),
tests: courseware.tests,
challengeSeed: courseware.challengeSeed,
cc: !!req.user,
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
coursewareHash: courseware._id,
environment: resources.whichEnvironment()
environment: resources.whichEnvironment(),
challengeType: courseware.challengeType
});
},
@ -110,14 +117,11 @@ exports.returnIndividualCourseware = function(req, res, next) {
details: courseware.description.slice(1),
tests: courseware.tests,
challengeSeed: courseware.challengeSeed,
cc: !!req.user,
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
coursewareHash: courseware._id,
environment: resources.whichEnvironment()
challengeType: courseware.challengeType
});
},
@ -129,13 +133,41 @@ exports.returnIndividualCourseware = function(req, res, next) {
details: courseware.description,
tests: courseware.tests,
video: courseware.challengeSeed[0],
cc: !!req.user,
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
coursewareHash: courseware._id,
environment: resources.whichEnvironment()
challengeType: courseware.challengeType
});
},
3: function() {
res.render('coursewares/showZiplineOrBasejump', {
title: courseware.name,
dashedName: dashedName,
name: courseware.name,
details: courseware.description,
video: courseware.challengeSeed[0],
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
coursewareHash: courseware._id,
challengeType: courseware.challengeType
});
},
4: function() {
res.render('coursewares/showZiplineOrBasejump', {
title: courseware.name,
dashedName: dashedName,
name: courseware.name,
details: courseware.description,
video: courseware.challengeSeed[0],
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
coursewareHash: courseware._id,
challengeType: courseware.challengeType
});
}
};
@ -173,7 +205,7 @@ exports.testCourseware = function(req, res) {
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
coursewares: [],
coursewareHash: "test"
coursewareHash: 'test'
});
};
@ -181,7 +213,7 @@ function getRidOfEmpties(elem) {
if (elem.length > 0) {
return elem;
}
};
}
exports.publicGenerator = function(req, res) {
res.render('courseware/public-generator');
@ -212,32 +244,132 @@ exports.generateChallenge = function(req, res) {
res.send(response);
};
exports.completedCourseware = function (req, res) {
exports.completedCourseware = function (req, res, next) {
var isCompletedDate = Math.round(+new Date() / 1000);
var isCompletedDate = Math.round(+new Date());
var coursewareHash = req.body.coursewareInfo.coursewareHash;
debug('this is the coursewarehash we got', coursewareHash);
req.user.completedCoursewares.push({
_id: coursewareHash,
completedDate: isCompletedDate,
name: req.body.coursewareInfo.coursewareName
name: req.body.coursewareInfo.coursewareName,
solution: null,
githubLink: null
});
var index = req.user.completedCoursewares.indexOf(coursewareHash);
debug('this is the index of the found courseware', index);
if (index === -1) {
req.user.progressTimestamps.push(Date.now() / 1000 | 0);
req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedCoursewares.splice(index, 1);
}
req.user.save(function (err, user) {
if (err) {
throw err;
return next(err);
}
if (user) {
res.send(true);
res.sendStatus(200);
}
});
};
exports.completedZiplineOrBasejump = function (req, res, next) {
debug('Inside controller for completed zipline or basejump with data %s',
req.body.coursewareInfo);
var isCompletedWith = req.body.coursewareInfo.completedWith || false;
var isCompletedDate = Math.round(+new Date());
var coursewareHash = req.body.coursewareInfo.coursewareHash;
var solutionLink = req.body.coursewareInfo.publicURL;
var githubLink = req.body.coursewareInfo.challengeType === '4'
? req.body.coursewareInfo.githubURL : true;
if (!solutionLink || !githubLink) {
req.flash('errors', {
msg: 'You haven\'t supplied the necessary URLs for us to inspect ' +
'your work.'
});
return res.sendStatus(403);
}
if (isCompletedWith) {
var paired = User.find({'profile.username': isCompletedWith.toLowerCase()}).limit(1);
paired.exec(function (err, pairedWith) {
if (err) {
return next(err);
} else {
var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
if (index > -1) {
req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedCoursewares.splice(index, 1);
}
pairedWith = pairedWith.pop();
req.user.completedCoursewares.push({
_id: coursewareHash,
completedWith: pairedWith._id,
completedDate: isCompletedDate,
solution: solutionLink,
githubLink: githubLink
});
req.user.save(function (err, user) {
if (err) {
return next(err);
}
debug('this is the user object returned %s,' +
' this is the req.user._id %s, ' +
'this is the pairedWith._id %s', user, req.user._id, pairedWith._id);
debug(req.user._id.toString() === pairedWith._id.toString());
if (req.user._id.toString() === pairedWith._id.toString()) {
return res.sendStatus(200);
}
index = pairedWith.uncompletedCoursewares.indexOf(coursewareHash);
if (index > -1) {
pairedWith.progressTimestamps.push(Date.now() || 0);
pairedWith.uncompletedCoursewares.splice(index, 1);
}
pairedWith.completedCoursewares.push({
_id: coursewareHash,
completedWith: req.user._id,
completedDate: isCompletedDate,
solution: solutionLink,
githubLink: githubLink
});
pairedWith.save(function (err, paired) {
if (err) {
return next(err);
}
if (user && paired) {
return res.sendStatus(200);
}
});
});
}
});
} else {
req.user.completedCoursewares.push({
_id: coursewareHash,
completedWith: null,
completedDate: isCompletedDate,
solution: solutionLink,
githubLink: githubLink
});
var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
if (index > -1) {
req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedCoursewares.splice(index, 1);
}
req.user.save(function (err, user) {
if (err) {
return next(err);
}
if (user) {
return res.sendStatus(200);
}
});
}
};

101
controllers/nonprofits.js Normal file
View File

@ -0,0 +1,101 @@
var async = require('async'),
User = require('../models/User'),
Challenge = require('./../models/Challenge'),
Bonfire = require('./../models/Bonfire'),
Story = require('./../models/Story'),
Comment = require('./../models/Comment'),
resources = require('./resources.json'),
steps = resources.steps,
secrets = require('./../config/secrets'),
moment = require('moment'),
https = require('https'),
debug = require('debug')('freecc:cntr:resources'),
cheerio = require('cheerio'),
request = require('request'),
R = require('ramda');
exports.nonprofitsHome = function(req, res) {
res.render('nonprofits/home', {
title: 'A guide to our Nonprofit Projects'
});
};
exports.areYouWithARegisteredNonprofit = function(req, res) {
res.render('nonprofits/are-you-with-a-registered-nonprofit', {
title: 'Are you with a with a registered nonprofit',
step: 1
});
};
exports.areTherePeopleThatAreAlreadyBenefitingFromYourServices = function(req, res) {
res.render('nonprofits/are-there-people-that-are-already-benefiting-from-your-services', {
title: 'Are there people already benefiting from your services',
step: 2
});
};
exports.okWithJavaScript = function(req, res) {
res.render('nonprofits/ok-with-javascript', {
title: 'Are you OK with us using JavaScript',
step: 3
});
};
exports.inExchangeWeAsk = function(req, res) {
res.render('nonprofits/in-exchange-we-ask', {
title: 'In exchange we ask that you ...',
step: 4
});
};
exports.howCanFreeCodeCampHelpYou = function(req, res) {
res.render('nonprofits/how-can-free-code-camp-help-you', {
title: 'Are you with a with a registered nonprofit',
step: 5
});
};
exports.whatDoesYourNonprofitDo = function(req, res) {
res.render('nonprofits/what-does-your-nonprofit-do', {
existingParams: req.params,
title: 'What does your nonprofit do?',
step: 6
});
};
exports.linkUsToYourWebsite = function(req, res) {
res.render('nonprofits/link-us-to-your-website', {
title: 'Link us to your website',
step: 7
});
};
exports.tellUsYourEmail = function(req, res) {
res.render('nonprofits/tell-us-your-email', {
title: 'Tell us your name',
step: 8
});
};
exports.tellUsYourName = function(req, res) {
res.render('nonprofits/tell-us-your-name', {
title: 'Tell us your name',
step: 9
});
};
exports.finishApplication = function(req, res) {
};
exports.yourNonprofitProjectApplicationHasBeenSubmitted = function(req, res) {
res.render('nonprofits/your-nonprofit-project-application-has-been-submitted', {
title: 'Your Nonprofit Project application has been submitted!'
});
};
exports.otherSolutions = function(req, res) {
res.render('nonprofits/other-solutions', {
title: 'Here are some other possible solutions for you'
});
};

View File

@ -150,6 +150,21 @@ module.exports = {
});
},
trelloCalls: function(req, res, next) {
request('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(err, status, trello) {
if (err) { return next(err); }
trello = (status && status.statusCode == 200) ? (JSON.parse(trello)) : "Can't connect to to Trello";
res.end(JSON.stringify(trello));
});
},
bloggerCalls: function(req, res, next) {
request('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function (err, status, blog) {
if (err) { return next(err); }
blog = (status && status.statusCode == 200) ? JSON.parse(blog) : "Can't connect to Blogger";
res.end(JSON.stringify(blog));
});
},
githubCalls: function(req, res) {
var githubHeaders = {headers: {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36'}, port:80 };
request('https://api.github.com/repos/freecodecamp/freecodecamp/pulls?client_id=' + secrets.github.clientID + '&client_secret=' + secrets.github.clientSecret, githubHeaders, function(err, status1, pulls) {
@ -161,31 +176,18 @@ module.exports = {
});
},
trelloCalls: function(req, res, next) {
request('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(err, status, trello) {
if (err) { return next(err); }
trello = (status && status.statusCode == 200) ? (JSON.parse(trello)).length : "Can't connect to to Trello";
res.send({"trello": trello});
trello = (status && status.statusCode === 200) ? (JSON.parse(trello)) : "Can't connect to to Trello";
res.end(JSON.stringify(trello));
});
},
bloggerCalls: function(req, res, next) {
request('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function (err, status, blog) {
if (err) { return next(err); }
blog = (status && status.statusCode == 200) ? JSON.parse(blog) : '';
res.send({
blog1Title: blog ? blog["items"][0]["title"] : "Can't connect to Blogger",
blog1Link: blog ? blog["items"][0]["url"] : "http://blog.freecodecamp.com",
blog2Title: blog ? blog["items"][1]["title"] : "Can't connect to Blogger",
blog2Link: blog ? blog["items"][1]["url"] : "http://blog.freecodecamp.com",
blog3Title: blog ? blog["items"][2]["title"] : "Can't connect to Blogger",
blog3Link: blog ? blog["items"][2]["url"] : "http://blog.freecodecamp.com",
blog4Title: blog ? blog["items"][3]["title"] : "Can't connect to Blogger",
blog4Link: blog ? blog["items"][3]["url"] : "http://blog.freecodecamp.com",
blog5Title: blog ? blog["items"][4]["title"] : "Can't connect to Blogger",
blog5Link: blog ? blog["items"][4]["url"] : "http://blog.freecodecamp.com"
});
blog = (status && status.statusCode === 200) ? JSON.parse(blog) : "Can't connect to Blogger";
res.end(JSON.stringify(blog));
});
},
@ -196,10 +198,12 @@ module.exports = {
req.user.save();
}
}
var date1 = new Date('10/15/2014');
var date1 = new Date("10/15/2014");
var date2 = new Date();
var progressTimestamps = req.user.progressTimestamps;
var now = Date.now() / 1000 | 0;
var now = Date.now() || 0;
if (req.user.pointsNeedMigration) {
var challengesHash = req.user.challengesHash;
for (var key in challengesHash) {
@ -208,22 +212,33 @@ module.exports = {
}
}
var timeStamps = [];
R.keys(req.user.challengesHash).forEach(function(key) {
"use strict";
timeStamps.push({timeStamp: challengesHash[key]});
var oldChallengeKeys = R.keys(req.user.challengesHash);
var updatedTimesFromOldChallenges = oldChallengeKeys.map(function(timeStamp) {
if (timeStamp.toString().length !== 13) {
timeStamp *= 1000;
}
return timeStamp;
});
req.user.completedCoursewares = Array.zip(timeStamps, coursewares,
var newTimeStamps = R.map(function(timeStamp) {
if (timeStamp.toString().length !== 13) {
timeStamp *= 1000;
}
return timeStamp;
}, req.user.progressTimestamps);
req.user.progressTimestamps = newTimeStamps;
req.user.completedCoursewares = Array.zip(updatedTimesFromOldChallenges, coursewares,
function(left, right) {
"use strict";
return ({
completedDate: left.timeStamp,
_id: right._id,
name: right.name
});
}).filter(function(elem) {
"use strict";
return elem.completedDate !== 0;
});
req.user.pointsNeedMigration = false;
@ -232,6 +247,7 @@ module.exports = {
if (progressTimestamps[progressTimestamps.length - 1] <= (now - 43200)) {
req.user.progressTimestamps.push(now);
}
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24));
var announcements = resources.announcements;
@ -260,6 +276,7 @@ module.exports = {
});
},
randomPhrase: function() {
var phrases = resources.phrases;
return phrases[Math.floor(Math.random() * phrases.length)];
@ -349,7 +366,6 @@ module.exports = {
return process.env.NODE_ENV;
},
getURLTitle: function(url, callback) {
debug('got url in meta scraping function', url);
(function () {
var result = {title: '', image: '', url: '', description: ''};
request(url, function (error, response, body) {

View File

@ -1,8 +1,7 @@
{
"announcements": [
["Some of Code School's courses are no longer free. We're switching to NodeSchool.io for our Node.js and Express.js challenges.", "http://freecodecamp.com/nodeschool-challenges"],
["Screen Hero is now free on Windows and Mac! Follow these special instructions to install it.", "http://freecodecamp.com/install-screenhero"],
["Once you finish all the challenges, we welcome you to attend our Nonprofit Project Office Hours every Monday and Thursday Night at 9 pm EST.", "https://gitter.im/FreeCodeCamp/NonprofitProjects"]
["Screen Hero is now free on Windows and Mac! Follow these special instructions to install it.", "http://freecodecamp.com/install-screenhero"]
],
"questions": [{
"question": "Time Complexity of Accessing Array Index (int a = ARR[5];)",

View File

@ -1,3 +1,4 @@
/* eslint-disable no-catch-shadow, no-unused-vars */
var R = require('ramda'),
debug = require('debug')('freecc:cntr:story'),
Story = require('./../models/Story'),
@ -24,11 +25,10 @@ function hotRank(timeValue, rank) {
}
exports.hotJSON = function(req, res) {
exports.hotJSON = function(req, res, next) {
var story = Story.find({}).sort({'timePosted': -1}).limit(1000);
story.exec(function(err, stories) {
if (err) {
res.send(500);
return next(err);
}
@ -38,7 +38,8 @@ exports.hotJSON = function(req, res) {
return res.json(stories.map(function(elem) {
return elem;
}).sort(function(a, b) {
return hotRank(b.timePosted - foundationDate, b.rank, b.headline) - hotRank(a.timePosted - foundationDate, a.rank, a.headline);
return hotRank(b.timePosted - foundationDate, b.rank, b.headline)
- hotRank(a.timePosted - foundationDate, a.rank, a.headline);
}).slice(0, sliceVal));
});
@ -48,36 +49,35 @@ exports.recentJSON = function(req, res, next) {
var story = Story.find({}).sort({'timePosted': -1}).limit(100);
story.exec(function(err, stories) {
if (err) {
res.status(500);
return next(err);
}
res.json(stories);
return res.json(stories);
});
};
exports.hot = function(req, res) {
res.render('stories/index', {
return res.render('stories/index', {
title: 'Hot stories currently trending on Camper News',
page: 'hot'
});
};
exports.submitNew = function(req, res) {
res.render('stories/index', {
return res.render('stories/index', {
title: 'Submit a new story to Camper News',
page: 'submit'
});
};
exports.search = function(req, res) {
res.render('stories/index', {
return res.render('stories/index', {
title: 'Search the archives of Camper News',
page: 'search'
});
};
exports.recent = function(req, res) {
res.render('stories/index', {
return res.render('stories/index', {
title: 'Recently submitted stories on Camper News',
page: 'recent'
});
@ -104,7 +104,7 @@ exports.preSubmit = function(req, res) {
var image = data.image || '';
var description = data.description || '';
return res.render('stories/index', {
title: "Confirm your Camper News story submission",
title: 'Confirm your Camper News story submission',
page: 'storySubmission',
storyURL: data.url,
storyTitle: title,
@ -121,7 +121,7 @@ exports.returnIndividualStory = function(req, res, next) {
Story.find({'storyLink': new RegExp(storyName, 'i')}, function(err, story) {
if (err) {
next(err);
return next(err);
}
@ -143,7 +143,7 @@ exports.returnIndividualStory = function(req, res, next) {
try {
var votedObj = story.upVotes.filter(function(a) {
return a['upVotedByUsername'] === req.user['profile']['username'];
})
});
if (votedObj.length > 0) {
userVoted = true;
}
@ -168,11 +168,14 @@ exports.returnIndividualStory = function(req, res, next) {
});
};
exports.getStories = function(req, res) {
exports.getStories = function(req, res, next) {
MongoClient.connect(secrets.db, function(err, database) {
if (err) {
return next(err);
}
database.collection('stories').find({
"$text": {
"$search": req.body.data.searchValue
'$text': {
'$search': req.body.data.searchValue
}
}, {
headline: 1,
@ -187,19 +190,22 @@ exports.getStories = function(req, res) {
storyLink: 1,
metaDescription: 1,
textScore: {
$meta: "textScore"
$meta: 'textScore'
}
}, {
sort: {
textScore: {
$meta: "textScore"
$meta: 'textScore'
}
}
}).toArray(function(err, items) {
if (err) {
return next(err);
}
if (items !== null && items.length !== 0) {
return res.json(items);
}
return res.status(404);
return res.sendStatus(404);
});
});
};
@ -208,7 +214,6 @@ exports.upvote = function(req, res, next) {
var data = req.body.data;
Story.find({'_id': data.id}, function(err, story) {
if (err) {
res.status(500);
return next(err);
}
story = story.pop();
@ -221,6 +226,15 @@ exports.upvote = function(req, res, next) {
);
story.markModified('rank');
story.save();
User.find({'_id': story.author.userId}, function(err, user) {
'use strict';
if (err) {
return next(err);
}
user = user.pop();
user.progressTimestamps.push(Date.now());
user.save();
});
return res.send(story);
});
};
@ -229,7 +243,6 @@ exports.comments = function(req, res, next) {
var data = req.params.id;
Comment.find({'_id': data}, function(err, comment) {
if (err) {
res.status(500);
return next(err);
}
comment = comment.pop();
@ -237,9 +250,9 @@ exports.comments = function(req, res, next) {
});
};
exports.newStory = function(req, res) {
exports.newStory = function(req, res, next) {
if (!req.user) {
return res.status(500);
return next(new Error('Must be logged in'));
}
var url = req.body.data.url;
var cleanURL = sanitizeHtml(url, {
@ -261,7 +274,7 @@ exports.newStory = function(req, res) {
}
Story.find({'link': url}, function(err, story) {
if (err) {
return res.status(500);
return next(err);
}
if (story.length) {
req.flash('errors', {
@ -296,10 +309,10 @@ exports.newStory = function(req, res) {
}
};
exports.storySubmission = function(req, res) {
exports.storySubmission = function(req, res, next) {
var data = req.body.data;
if (req.user._id.toString() !== data.author.userId.toString()) {
return res.status(500);
return next(new Error('Not authorized'));
}
var storyLink = data.headline
.replace(/\'/g, '')
@ -332,9 +345,12 @@ exports.storySubmission = function(req, res) {
metaDescription: data.storyMetaDescription
});
req.user.progressTimestamps.push(Date.now());
req.user.save();
story.save(function(err) {
if (err) {
return res.status(500);
return next(err);
}
res.send(JSON.stringify({
storyLink: story.storyLink.replace(/\s/g, '-').toLowerCase()
@ -342,10 +358,10 @@ exports.storySubmission = function(req, res) {
});
};
exports.commentSubmit = function(req, res) {
exports.commentSubmit = function(req, res, next) {
var data = req.body.data;
if (req.user._id.toString() !== data.author.userId.toString()) {
return res.status(500);
return next(new Error('Not authorized'));
}
var sanitizedBody = sanitizeHtml(data.body,
{
@ -368,14 +384,14 @@ exports.commentSubmit = function(req, res) {
topLevel: true,
commentOn: Date.now()
});
commentSave(comment, Story, res);
commentSave(comment, Story, res, next);
};
exports.commentOnCommentSubmit = function(req, res) {
exports.commentOnCommentSubmit = function(req, res, next) {
var data = req.body.data;
if (req.user._id.toString() !== data.author.userId.toString()) {
return res.status(500);
return next(new Error('Not authorized'));
}
var sanitizedBody = sanitizeHtml(data.body,
@ -399,25 +415,25 @@ exports.commentOnCommentSubmit = function(req, res) {
topLevel: false,
commentOn: Date.now()
});
commentSave(comment, Comment, res);
commentSave(comment, Comment, res, next);
};
function commentSave(comment, Context, res) {
function commentSave(comment, Context, res, next) {
comment.save(function(err, data) {
if (err) {
return res.status(500);
return next(err);
}
try {
Context.find({'_id': comment.associatedPost}, function (err, associatedStory) {
if (err) {
return res.status(500);
return next(err);
}
associatedStory = associatedStory.pop();
if (associatedStory) {
associatedStory.comments.push(data._id);
associatedStory.save(function (err) {
if (err) {
res.status(500);
return next(err);
}
res.send(true);
});
@ -425,7 +441,7 @@ function commentSave(comment, Context, res) {
});
} catch (e) {
// delete comment
return res.status(500);
return next(err);
}
});
}

View File

@ -6,9 +6,9 @@ var _ = require('lodash'),
User = require('../models/User'),
secrets = require('../config/secrets'),
moment = require('moment'),
Challenge = require('./../models/Challenge'),
debug = require('debug')('freecc:cntr:challenges'),
resources = require('./resources');
resources = require('./resources'),
R = require('ramda');
@ -18,7 +18,9 @@ var _ = require('lodash'),
*/
exports.getSignin = function(req, res) {
if (req.user) return res.redirect('/');
if (req.user) {
return res.redirect('/');
}
res.render('account/signin', {
title: 'Free Code Camp Login'
});
@ -41,13 +43,17 @@ exports.postSignin = function(req, res, next) {
}
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (err) {
return next(err);
}
if (!user) {
req.flash('errors', { msg: info.message });
return res.redirect('/signin');
}
req.logIn(user, function(err) {
if (err) return next(err);
if (err) {
return next(err);
}
req.flash('success', { msg: 'Success! You are logged in.' });
res.redirect(req.session.returnTo || '/');
});
@ -70,7 +76,9 @@ exports.signout = function(req, res) {
*/
exports.getEmailSignin = function(req, res) {
if (req.user) return res.redirect('/');
if (req.user) {
return res.redirect('/');
}
res.render('account/email-signin', {
title: 'Sign in to your Free Code Camp Account'
});
@ -82,7 +90,9 @@ exports.getEmailSignin = function(req, res) {
*/
exports.getEmailSignup = function(req, res) {
if (req.user) return res.redirect('/');
if (req.user) {
return res.redirect('/');
}
res.render('account/email-signup', {
title: 'Create Your Free Code Camp Account'
});
@ -174,7 +184,7 @@ exports.postEmailSignup = function(req, res, next) {
'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\n',
'Feel free to email us at this address if you have any questions about Free Code Camp.\n',
"And if you have a moment, check out our blog: blog.freecodecamp.com.\n",
'And if you have a moment, check out our blog: blog.freecodecamp.com.\n',
'Good luck with the challenges!\n\n',
'- the Volunteer Camp Counselor Team'
].join('')
@ -186,19 +196,6 @@ exports.postEmailSignup = function(req, res, next) {
});
};
/**
* For Calendar display
*/
exports.getStreak = function(req, res) {
var completedStreak = req.user.challengesHash;
}
/**
* GET /account
* Profile page.
*/
exports.getAccount = function(req, res) {
res.render('account/account', {
@ -269,10 +266,40 @@ exports.returnUser = function(req, res, next) {
if (user[0]) {
var user = user[0];
user.progressTimestamps = user.progressTimestamps.sort(function(a, b) {
return a - b;
});
var timeObject = Object.create(null);
R.forEach(function(time) {
timeObject[moment(time).format('YYYY-MM-DD')] = time;
}, user.progressTimestamps);
var tmpLongest = 1;
var timeKeys = R.keys(timeObject);
for (var i = 1; i <= timeKeys.length; i++) {
if (moment(timeKeys[i - 1]).add(1, 'd').toString()
=== moment(timeKeys[i]).toString()) {
tmpLongest++;
if (tmpLongest > user.currentStreak) {
user.currentStreak = tmpLongest;
}
if ( user.currentStreak > user.longestStreak) {
user.longestStreak = user.currentStreak;
}
}
}
user.save(function(err) {
if (err) {
return next(err);
}
});
var data = {};
var progressTimestamps = user.progressTimestamps;
for (var i = 0; i < progressTimestamps.length; i++) {
data[progressTimestamps[i].toString()] = 1;
data[(progressTimestamps[i] / 1000).toString()] = 1;
}
res.render('account/show', {
@ -299,7 +326,9 @@ exports.returnUser = function(req, res, next) {
website3Image: user.portfolio.website3Image,
ch: user.challengesHash,
calender: data,
moment: moment
moment: moment,
longestStreak: user.longestStreak,
currentStreak: user.currentStreak
});
} else {

21
controllers/ziplines.js Normal file
View File

@ -0,0 +1,21 @@
var async = require('async'),
User = require('../models/User'),
Challenge = require('./../models/Challenge'),
Bonfire = require('./../models/Bonfire'),
Story = require('./../models/Story'),
Comment = require('./../models/Comment'),
resources = require('./resources.json'),
steps = resources.steps,
secrets = require('./../config/secrets'),
moment = require('moment'),
https = require('https'),
debug = require('debug')('freecc:cntr:resources'),
cheerio = require('cheerio'),
request = require('request'),
R = require('ramda');
nonprofitHome: function nonprofitHome(req, res) {
res.render('nonprofits/home', {
title: 'A guide to our Nonprofit Projects'
});
}

22
models/Basejump.js Normal file
View File

@ -0,0 +1,22 @@
var mongoose = require('mongoose');
var secrets = require('../config/secrets');
/**
*
* @type {exports.Schema}
*/
var basejumpSchema = new mongoose.Schema({
name: {
type: String,
unique: true
},
picture: String,
video: String,
gitHubLink: String,
demoLink: String,
details: Array
});
module.exports = mongoose.model('Basejump', basejumpSchema);

View File

@ -15,7 +15,8 @@ var bonfireSchema = new mongoose.Schema({
difficulty: String,
description: Array,
tests: Array,
challengeSeed: String
challengeSeed: String,
MDNlinks: [String]
});
module.exports = mongoose.model('Bonfire', bonfireSchema);

View File

@ -1,11 +0,0 @@
var mongoose = require('mongoose');
var secrets = require('../config/secrets');
var bonfireCompletionSchema = new mongoose.Schema({
dateCompleted: Number,
completedWith: ObjectId,
bonfireHash: ObjectId,
solution: String
});
module.exports = mongoose.model('BonfireCompletion', bonfireCompletionSchema);

31
models/Nonprofit.js Normal file
View File

@ -0,0 +1,31 @@
var mongoose = require('mongoose');
var secrets = require('../config/secrets');
/**
*
* @type {exports.Schema}
*/
var nonprofitSchema = new mongoose.Schema({
name: String,
registeredNonprofit: true,
requestedDeliverables: Array,
existingUserbase: true,
acceptJavascript: true,
agreeToTerms: true,
whatDoesNonprofitDo: String,
websiteLink: String,
stakeholderName: String,
stakeholderEmail: String,
endUser: String,
approvedDeliverables: Array,
projectDescription: String,
logoUrl: String,
imageUrl: String,
interestedCampers: Array,
confirmedCampers: Array,
estimatedHours: String
});
module.exports = mongoose.model('Nonprofit', nonprofitSchema);

View File

@ -1,7 +1,9 @@
var bcrypt = require('bcrypt-nodejs');
var crypto = require('crypto');
var mongoose = require('mongoose');
require('mongoose-long')(mongoose);
var Long = mongoose.Types.Long;
var userSchema = new mongoose.Schema({
email: {
type: String,
@ -21,7 +23,7 @@ var userSchema = new mongoose.Schema({
type: Number,
default: 0
},
progressTimestamps: { type: Array, default: [] },
progressTimestamps: [],
challengesCompleted: { type: Array, default: [] },
pointsNeedMigration: { type: Boolean, default: true },
challengesHash: {
@ -332,9 +334,33 @@ var userSchema = new mongoose.Schema({
resetPasswordToken: String,
resetPasswordExpires: Date,
uncompletedBonfires: Array,
completedBonfires: Array,
completedBonfires: [
{
_id: String,
completedWith: String,
completedDate: Long,
solution: String
}
],
uncompletedCoursewares: Array,
completedCoursewares: Array
completedCoursewares: [
{
completedDate: Long,
_id: String,
name: String,
completedWith: String,
solution: String,
githubLink: String
}
],
currentStreak: {
type: Number,
default: 0
},
longestStreak: {
type: Number,
default: 0
}
});
/**

21
models/Zipline.js Normal file
View File

@ -0,0 +1,21 @@
var mongoose = require('mongoose');
var secrets = require('../config/secrets');
/**
*
* @type {exports.Schema}
*/
var ziplineSchema = new mongoose.Schema({
name: {
type: String,
unique: true
},
picture: String,
video: String,
codepenLink: String,
details: Array
});
module.exports = mongoose.model('Zipline', ziplineSchema);

View File

@ -15,9 +15,11 @@
"postinstall": "node seed_data/seed.js"
},
"dependencies": {
"accepts": "^1.2.5",
"async": "^0.9.0",
"bcrypt-nodejs": "^0.0.3",
"body-parser": "^1.9.3",
"chai-jquery": "^2.0.0",
"cheerio": "^0.18.0",
"clockwork": "^0.1.1",
"compression": "^1.2.1",
@ -45,11 +47,10 @@
"method-override": "^2.3.0",
"moment": "^2.8.4",
"mongodb": "^1.4.33",
"mongoose": "^3.8.19",
"mongoose-text-search": "0.0.2",
"mongoose": "^4.0.0",
"mongoose-long": "0.0.2",
"morgan": "^1.5.0",
"newrelic": "^1.13.3",
"node": "0.0.0",
"nodemailer": "^1.3.0",
"passport": "^0.2.1",
"passport-facebook": "^1.0.3",
@ -74,7 +75,6 @@
"chai": "^1.10.0",
"gulp": "^3.8.8",
"gulp-inject": "^1.0.2",
"gulp-minify-css": "^0.5.1",
"gulp-nodemon": "^1.0.4",
"mocha": "^2.0.1",
"multiline": "^1.0.1",

View File

@ -335,6 +335,10 @@ ul {
margin-bottom: -10px;
}
.nonprofit-landing {
font-size: 50px;
}
.big-text {
font-size: 63px;
}
@ -731,6 +735,11 @@ iframe.iphone {
}
}
.nonprofit-help-select-text-height {
font-size: 40px;
padding-top: 20px;
}
// To adjust right margin, negative values bring the image closer to the edge of the screen
.iphone-position {
position: absolute;
@ -827,6 +836,10 @@ iframe.iphone {
max-height: 110px;
}
.button-spacer {
padding: 3px 0 2px 0;
}
.spacer {
padding: 15px 0 15px 0;
}
@ -871,6 +884,10 @@ iframe.iphone {
background-color: #EEEEEE;
}
.checkbox-table label {
margin-left: 10px;
}
//uncomment this to see the dimensions of all elements outlined in red
//* {
// border-color: red;

View File

@ -250,7 +250,7 @@ var runTests = function(err, data) {
};
function showCompletion() {
var time = Math.floor(Date.now() / 1000) - started;
var time = Math.floor(Date.now()) - started;
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time +', Attempts: ' + attempts);
$('#complete-bonfire-dialog').modal('show');
$('#complete-bonfire-dialog').keydown(function(e) {

View File

@ -17,6 +17,7 @@ var run = function(code) {
}
application.remote.output(result);
self.close();
};

View File

@ -138,7 +138,7 @@ function doLinting () {
//$('#testSuite').empty();
function showCompletion() {
var time = Math.floor(Date.now() / 1000) - started;
var time = Math.floor(Date.now()) - started;
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time);
$('#next-courseware-button').removeAttr('disabled');
$('#next-courseware-button').addClass('animated tada');

View File

@ -235,7 +235,7 @@ var runTests = function(err, data) {
};
function showCompletion() {
var time = Math.floor(Date.now() / 1000) - started;
var time = Math.floor(Date.now()) - started;
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time +', Attempts: ' + attempts);
$('#complete-courseware-dialog').modal('show');
$('#complete-courseware-dialog').keydown(function(e) {

View File

@ -79,10 +79,8 @@ $(document).ready(function() {
$('#complete-courseware-dialog').modal('show');
});
$('#complete-courseware-dialog').on('keypress', function(e) {
if (e.ctrlKey && e.keyCode == 13) {
$('#next-courseware-button').click();
}
$('#completed-zipline-or-basejump').on('click', function() {
$('#complete-zipline-or-basejump-dialog').modal('show');
});
$('#complete-bonfire-dialog').on('hidden.bs.modal', function() {
@ -101,13 +99,16 @@ $(document).ready(function() {
editor.focus();
});
$('#complete-courseware-dialog').on('hidden.bs.modal', function() {
editor.focus();
});
$('#next-courseware-button').on('click', function() {
console.log(passedCoursewareHash);
if ($('.signup-btn-nav').length < 1) {
switch (challengeType) {
case 0:
case 1:
case 2:
$.post(
'/completed-courseware/',
{
@ -122,6 +123,52 @@ $(document).ready(function() {
}
}
);
break;
case 3:
var didCompleteWith = $('#completed-with').val() || null;
var publicURL = $('#public-url').val() || null;
$.post(
'/completed-zipline-or-basejump/',
{
coursewareInfo: {
coursewareHash: passedCoursewareHash,
coursewareName: passedCoursewareName,
completedWith: didCompleteWith,
publicURL: publicURL,
challengeType: challengeType
}
}).success(
function() {
window.location.href = '/challenges';
}).fail(
function() {
window.location.href = '/challenges';
});
break;
case 4:
var didCompleteWith = $('#completed-with').val() || null;
var publicURL = $('#public-url').val() || null;
var githubURL = $('#github-url').val() || null;
$.post(
'/completed-zipline-or-basejump/',
{
coursewareInfo: {
coursewareHash: passedCoursewareHash,
coursewareName: passedCoursewareName,
completedWith: didCompleteWith,
publicURL: publicURL,
githubURL: githubURL,
challengeType: challengeType
}
}).success(function() {
window.location.href = '/challenges';
}).fail(function() {
window.location.replace(window.location.href);
});
break;
default:
break;
}
}
});
@ -132,7 +179,7 @@ $(document).ready(function() {
});
$('#showAllButton').on('click', function() {
$('#all-bonfires-dialog').modal('show');
$('#all-challenges-dialog').modal('show');
});
$('.next-challenge-button').on('click', function() {

View File

@ -0,0 +1,66 @@
// MDN Links
/* These links are for Bonfires. Each key/value pair is used to render a Bonfire with approrpiate links.
The text of the key is what the link text will be, e.g. <a href="https://developer ...">Global Array Object</a>
General convention is to use the page title of the MDN reference page.
*/
var links =
{
// ========= GLOBAL OBJECTS
"Global Array Object" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",
"Global Object" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",
"Global String Object" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String",
"Boolean Objects" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean",
// ========= PROPERTIES/MISC
"String.length" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length",
"Arguments object" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments",
// ========== OBJECT METHODS
"Object.getOwnPropertyNames()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames",
"Object.keys()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys",
"Object.hasOwnProperty()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty",
// ======== STRING METHODS
"String.charAt()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt",
"String.charCodeAt()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt",
"String.concat()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat",
"String.indexOf()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf",
"String.lastIndexOf()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf",
"String.match()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match",
"String.replace()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace",
"String.slice()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice",
"String.split()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split",
"String.substring()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring",
"String.substr()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr",
"String.toLowerCase()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase",
"String.toString()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toString",
"String.toUpperCase()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase",
// ======== ARRAY METHODS
"Array.concat()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat",
"Array.every()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every",
"Array.filter()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter",
"Array.forEach()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach",
"Array.indexOf()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf",
"Array.join()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join",
"Array.lastIndexOf()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf",
"Array.map()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map",
"Array.pop()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop",
"Array.push()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push",
"Array.reduce()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce",
"Array.reverse()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse",
"Array.slice()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice",
"Array.some()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some",
"Array.sort()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort",
"Array.splice()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice",
"Array.toString()" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString",
// ======== GENERAL JAVASCRIPT REFERENCES
"Arithmetic Operators" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators",
"Comparison Operators" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"
};
module.exports = links;

View File

@ -31,7 +31,8 @@
"You may need to turn the string into an array before you can reverse it.",
"Your result must be a string."
],
"challengeSeed": "function reverseString(str) {\n return str;\r\n}\n\nreverseString('hello');"
"challengeSeed": "function reverseString(str) {\n return str;\r\n}\n\nreverseString('hello');",
"MDNlinks" : ["Global String Object", "String.split()", "Array.reverse()", "Array.join()"]
},
{
"_id": "a302f7aae1aa3152a5b413bc",
@ -49,7 +50,8 @@
"Factorials are often represented with the shorthand notation n!",
"For example: 5! = 1 * 2 * 3 * 4 * 5 = 120f"
],
"challengeSeed": "function factorialize(num) {\n return num;\r\n}\n\nfactorialize(5);"
"challengeSeed": "function factorialize(num) {\n return num;\r\n}\n\nfactorialize(5);",
"MDNlinks" : ["Arithmetic Operators"]
},
{
"_id": "aaa48de84e1ecc7c742e1124",
@ -70,7 +72,8 @@
"assert.deepEqual(palindrome(\"never odd or even\"), true);",
"assert.deepEqual(palindrome(\"nope\"), false);"
],
"challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n\n\npalindrome(\"eye\");"
"challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n\n\npalindrome(\"eye\");",
"MDNlinks" : ["String.replace()", "String.toLowerCase()"]
},
{
"_id": "a26cbbe9ad8655a977e1ceb5",
@ -87,7 +90,8 @@
"expect(findLongestWord('May the force be with you')).to.equal(5);",
"expect(findLongestWord('Google do a barrel roll')).to.equal(6);",
"expect(findLongestWord('What is the average airspeed velocity of an unladen swallow')).to.equal(8);"
]
],
"MDNlinks" : ["String.split()", "String.length"]
},
{
"_id": "ab6137d4e35944e21037b769",
@ -103,7 +107,8 @@
"expect(titleCase(\"I'm a little tea pot\")).to.equal(\"I'm A Little Tea Pot\");",
"expect(titleCase(\"sHoRt AnD sToUt\")).to.equal(\"Short And Stout\");",
"expect(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\")).to.equal(\"Here Is My Handle Here Is My Spout\");"
]
],
"MDNlinks" : ["String.charAt()"]
},
{
"_id": "a789b3483989747d63b0e427",
@ -119,7 +124,8 @@
"expect(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).to.be.a('array');",
"(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).should.eql([5,27,39,1001]);",
"assert(largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]).should.eql([9,35,97,1000000]));"
]
],
"MDNlinks" : ["Comparison Operators"]
},
{
"_id": "acda2fb1324d9b0fa741e6b5",
@ -134,7 +140,8 @@
"assert.strictEqual(end('Bastian', 'n'), true, 'should equal true if target equals end of string');",
"assert.strictEqual(end('He has to give me a new name', 'name'), true, 'should equal true if target equals end of string');",
"assert.strictEqual(end('If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing', 'mountain'), false, 'should equal false if target does not equal end of string');"
]
],
"MDNlinks" : ["String.substr()"]
},
{
"_id": "afcc8d540bea9ea2669306b6",
@ -148,7 +155,8 @@
"assert.strictEqual(repeat('*', 3), '***', 'should repeat a string n times');",
"assert.strictEqual(repeat('abc', 3), 'abcabcabc', 'should repeat a string n times');",
"assert.strictEqual(repeat('abc', -2), '', 'should return an empty string for negative numbers');"
]
],
"MDNlinks" : ["Global String Object"]
},
{
"_id": "ac6993d51946422351508a41",
@ -163,7 +171,8 @@
"expect(truncate('A-tisket a-tasket A green and yellow basket', 11)).to.eqls('A-tisket...');",
"assert(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length) === 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is = length');",
"assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length + 2), 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is < length');"
]
],
"MDNlinks" : ["String.slice()"]
},
{
"_id": "a9bd25c716030ec90084d8a1",
@ -176,8 +185,9 @@
"tests": [
"assert.deepEqual(chunk(['a', 'b', 'c', 'd'], 2), [['a', 'b'], ['c', 'd']], 'should return chunked arrays');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], 'should return chunked arrays');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'should return cthe last chunk as remaining elements');"
]
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'should return the last chunk as remaining elements');"
],
"MDNlinks" : ["Array.push()"]
},
{
"_id": "ab31c21b530c0dafa9e241ee",
@ -191,7 +201,8 @@
"assert.deepEqual(slasher([1, 2, 3], 2), [3], 'should drop the first two elements');",
"assert.deepEqual(slasher([1, 2, 3], 0), [1, 2, 3], 'should return all elements when n < 1');",
"assert.deepEqual(slasher([1, 2, 3], 9), [], 'should return an empty array when n >= array.length');"
]
],
"MDNlinks" : ["Array.slice()", "Array.splice()"]
},
{
"_id": "af2170cad53daa0770fabdea",
@ -210,7 +221,8 @@
"expect(mutation(['zyxwvutsrqponmlkjihgfedcba', 'qrstu'])).to.be.true;",
"expect(mutation(['Mary', 'Army'])).to.be.true;",
"expect(mutation(['Alien', 'line'])).to.be.true;"
]
],
"MDNlinks" : ["Array.sort()"]
},
{
"_id": "adf08ec01beb4f99fc7a68f2",
@ -225,7 +237,8 @@
"assert.deepEqual(bouncer([7, 'ate', '', false, 9]), [7, 'ate', 9], 'should remove falsey values');",
"assert.deepEqual(bouncer(['a', 'b', 'c']), ['a', 'b', 'c'], 'should return full array if no falsey elements');",
"assert.deepEqual(bouncer([false, null, 0]), [], 'should return empty array if all elements are falsey');"
]
],
"MDNlinks" : ["Boolean Objects", "Array.filter()"]
},
{
"_id":"a8e512fbe388ac2f9198f0fa",
@ -238,7 +251,8 @@
"tests":[
"assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');",
"assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], 'should return with multiples');"
]
],
"MDNlinks" : ["Global Object", "Object.hasOwnProperty()", "Object.keys()"]
},
{
"_id":"a39963a4c10bc8b4d4f06d7e",
@ -251,7 +265,8 @@
"tests": [
"assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');",
"assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');"
]
],
"MDNlinks" : ["Array.filter()"]
},
{
"_id": "a24c1a4622e3c05097f71d67",
@ -317,7 +332,8 @@
"Convert the number be a roman numeral.",
"All <a href=\"http://www.mathsisfun.com/roman-numerals.html\">roman numerals</a> answers should be provided in upper-case."
],
"challengeSeed": "function convert(num) {\n return num;\r\n}\n\nconvert(36);"
"challengeSeed": "function convert(num) {\n return num;\r\n}\n\nconvert(36);",
"MDNlinks" : ["Array.splice()", "Array.indexOf()", "Array.join()"]
},
{
"_id": "a0b5010f579e69b815e7c5d6",
@ -336,7 +352,8 @@
"Second argument is the word that you will be replacing (before).",
"Third argument is what you will be replacing the second argument with (after)."
],
"challengeSeed": "function replace(str, before, after) {\n return str;\r\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");"
"challengeSeed": "function replace(str, before, after) {\n return str;\r\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");",
"MDNlinks" : ["Array.splice()", "String.replace()", "Array.join()"]
},
{
"_id": "aa7697ea2477d1316795783b",
@ -354,7 +371,8 @@
"<a href=\"http://en.wikipedia.org/wiki/Pig_Latin\">Pig Latin</a> takes the first consonant (or consonant cluster) of an English word, moves it to the end of the word and suffixes an \"ay\".",
"If a word begins with a vowel you just add \"way\" to the end."
],
"challengeSeed": "function translate(str) {\n return str;\r\n}\n\ntranslate(\"consonant\");"
"challengeSeed": "function translate(str) {\n return str;\r\n}\n\ntranslate(\"consonant\");",
"MDNlinks" : ["Array.indexOf()", "Array.push()", "Array.join()", "String.substr()", "String.split()"]
},
{
"_id": "afd15382cdfb22c9efe8b7de",
@ -370,7 +388,8 @@
"<a href=\"http://en.wikipedia.org/wiki/Base_pair\">Base pairs</a> are a pair of AT and CG. Match the missing element to the provided character.",
"Return the provided character as the first element in each array."
],
"challengeSeed": "function pair(str) {\n return str;\r\n}\n\npair(\"GCG\");"
"challengeSeed": "function pair(str) {\n return str;\r\n}\n\npair(\"GCG\");",
"MDNlinks" : ["Array.push()", "String.split()"]
},
{
"_id": "af7588ade1100bde429baf20",
@ -759,6 +778,7 @@
"assert.deepEqual(friendly(['2016-03-01', '2016-05-05']), ['March 1st','May 5th, 2016']);",
"assert.deepEqual(friendly(['2017-01-01', '2017-01-01']), ['January 1st, 2017'], 'since we do not duplicate only return once');",
"assert.deepEqual(friendly(['2022-09-05', '2023-09-04']), ['September 5th, 2022','September 4th, 2023']);"
]
],
"MDNlinks" : ["String.split()", "String.substr()", "parseInt()"]
}
]

View File

@ -1,663 +0,0 @@
[
{
"name": "Learn how Free Code Camp Works",
"time": 2,
"video": "114486344",
"challengeNumber": 0,
"steps": [
"Watch this 1-minute video, or simply read this summary:",
"Welcome to Free Code Camp. We're a community of busy people learning to code.",
"We built this community because learning to code is hard. But anyone who can stay motivated can learn to code. And the best way to stay motivated is to code with friends.",
"To maximize accessibility, all our challenges are self-paced, browser-based, and free.",
"All of us start with the same 100 hours of interactive coding challenges. These cover Computer Science and databases. They also cover in-demand JavaScript tools like jQuery, Node.js and MongoDB.",
"Once we have a basic understanding of web development, we'll spend another 900 hours putting that theory into practice. We'll build full stack solutions for nonprofits.",
"By the end of this process, we'll be good at coding. We'll have a portfolio of apps with happy users to prove it. We'll also have an alumni network of fellow coders and nonprofits ready to serve as references.",
"If you make it through Free Code Camp, you will be able to get a coding job. There are far more job openings out there than there are qualified coders to fill them.",
"Also, for every pure coding job, there are at least 5 additional jobs that require some coding skills. So even if you decide not to pursue coding as a career, you'll still walk away with a valuable job skill.",
"There are 3 keys to succeeding in our community: do the challenges, make friends, and find a routine.",
"Now it's time to join our chatroom. Click the \"I've completed this challenge\" button to move on to your next challenge."
]
},
{
"name": "Join Our Chat Room",
"time": 5,
"video": "114627322",
"challengeNumber": 1,
"steps": [
"Now we're going to join the Free Code Camp chat room. You can come here any time of day to hang out, ask questions, or find another camper who's on the same challenge as you and wants to pair program.",
"If you don't already have a GitHub account, create one real quick at <a href='https://www.github.com' target='_blank'>https://www.github.com</a>.",
"Be sure to update your biographical information and upload an image. A picture of your face works best. This is how people will see you in the chat room, so put your best foot forward.",
"Now enter the chat room by going to <a href='https://gitter.im/FreeCodeCamp/FreeCodeCamp' target='_blank'>https://gitter.im/FreeCodeCamp/FreeCodeCamp</a> and clicking the \"sign in with GitHub\" button.",
"Introduce yourself to our chat room by typing: \"hello world!\".",
"Tell your fellow campers how you found Free Code Camp. Also tell us why you want to learn to code.",
"Keep the chat room open while you work through the other challenges. That way you ask for help if you get stuck on a challenge. You can also socialize when you feel like taking a break.",
"Now that you've completed this challenge, you can go directly your most-recently visited chat room by clicking the \"Chat\" button in the navigation bar above."
]
},
{
"name": "Join Our Forum (currently disabled)",
"time": 5,
"video": "115275066",
"challengeNumber": 2,
"steps": [
"Go to Free Code Camp's forum: <a href='http://forum.freecodecamp.com' target='_blank'>http://forum.freecodecamp.com</a>.",
"You can come here to share and discuss coding resources, ask questions to our entire community, and coordinate local Free Code Camp events.",
"Our chat room is great for realtime discussions, but our forum is ideal for longer-term discussions and open-ended questions.",
"Sign in with the Github account you created during Challenge 1.",
"Click on the \"Introduce yourself here\" discussion.",
"Here you can read through other Free Code Camp community members' self introductions.",
"Go ahead and type a brief self introduction of your own.",
"Click on the \"Categories\" drop-down menu. You should see a category called \"Local Chapters\". Click that. If your city isn't already on the list, create a topic for it. Otherwise, introduce yourself to the other campers from your city.",
"Come back here daily to ask questions, engage in discussions, and share links to helpful coding tools.",
"Now that you've completed this challenge, you can go directly to the forum by clicking the \"Forum\" button in the navigation bar above."
]
},
{
"name": "Build a Personal Website",
"time": 60,
"video": "114627406",
"challengeNumber": 3,
"steps": [
"There are tons of interactive HTML and CSS tutorials out there, but Nathan Bashaw and Christine Bower's Dash tutorials - which they built for General Assembly - are our favorite.",
"Go to <a href='https://dash.generalassemb.ly/projects/annas-website-1' target='_blank'>https://dash.generalassemb.ly/projects/annas-website-1</a> and get started with your first project."]
},
{
"name": "Build a Responsive Blog Theme",
"time": 60,
"video": "114578441",
"challengeNumber": 4,
"steps": [
"Next, let's learn about responsive web design and continue learning about HTML and CSS.",
"A responsive website will automatically adapt to changes in your browser's width. This means that you can make one version of a website that will look good on desktop, tablet and phone.",
"Later, we'll use Twitter's Bootstrap CSS framework to build responsive websites.",
"You can check it out here: <a href='http://getbootstrap.com/' target='_blank'>http://getbootstrap.com/</a>.",
"Go to <a href='https://dash.generalassemb.ly/projects/jeffs-blog-1' target='_blank'>https://dash.generalassemb.ly/projects/jeffs-blog-1</a> and complete the second project."
]
},
{
"name": "Build a Small Business Website",
"time": 60,
"video": "114578438",
"challengeNumber": 5,
"steps": [
"Ready for some more HTML and CSS fundamentals?",
"Go to <a href='https://dash.generalassemb.ly/projects/eshas-restaurant-1' target='_blank'>https://dash.generalassemb.ly/projects/eshas-restaurant-1</a> and complete the third project."]
},
{
"name": "Tweak HTML and CSS in CodePen",
"time": 10,
"video": "110752744",
"challengeNumber": 6,
"steps": [
"Now we're going to learn how to use a tool called CodePen, which lets you experiment with HTML and CSS, and even create single-page web applications, right in your browser!",
"Go to <a href='http://www.newsweek.com/' target='_blank'>http://www.newsweek.com/</a>",
"Change the window size. Note that Newsweek.com is using <strong>Responsive Design</strong>.",
"Right-click an area of the page that doesn't have any HTML elements on it, then choose 'view page source'.",
"Select all the text, then copy it.",
"Go to <a href='http://codepen.io/pen/' target='_blank'>http://codepen.io/pen/</a>",
"Paste the HTML you copied from Newsweek.com into the HTML field of CodePen.",
"You now have your own customizable version of the Newsweek.com website. See if you can change some of the text and images."
]
},
{
"name": "Build a CSS Robot",
"time": 60,
"video": "114578436",
"challengeNumber": 7,
"steps": [
"Now let's learn some more CSS, and a small amount of a JavaScript-based tool called jQuery.",
"Go to <a href='https://dash.generalassemb.ly/projects/cotbots-1' target='_blank'>https://dash.generalassemb.ly/projects/cotbots-1</a> and complete the fourth project."]
},
{
"name": "Get Started with jQuery",
"time": 30,
"video": "114578435",
"challengeNumber": 8,
"steps": [
"jQuery is a powerful tool for manipulating HTML elements.",
"It's a lot easier to use than JavaScript itself, so we'll learn it first.",
"It's also extremely popular with employers, so we're going to learn it well.",
"Code School has an excellent free course that will walk us through the basics of jQuery.",
"Go to <a href='http://try.jquery.com/levels/1/challenges/1' target='_blank'>http://try.jquery.com/levels/1/challenges/1</a> and complete the first section."
]
},
{
"name": "Traverse the DOM",
"time": 30,
"video": "114591805",
"challengeNumber": 9,
"steps": [
"Now let's learn more about DOM traversal - that is, moving from one HTML element to the next.",
"Go to <a href='http://try.jquery.com/levels/2/challenges/1' target='_blank'>http://try.jquery.com/levels/2/challenges/1</a> and complete the second section."
]
},
{
"name": "Work with the DOM",
"time": 30,
"video": "114591804",
"challengeNumber": 10,
"steps": [
"Let's learn some more advanced ways to use jQuery to manipulate the DOM.",
"Go to <a href='http://try.jquery.com/levels/3/challenges/1' target='_blank'>http://try.jquery.com/levels/3/challenges/1</a> and complete the third section."
]
},
{
"name": "Listen for DOM Events",
"time": 30,
"video": "114591802",
"challengeNumber": 11,
"steps": [
"Now let's learn how to use jQuery Listeners. These will \"listen\" for something to happen, and then trigger a subsequent event",
"Go to <a href='http://try.jquery.com/levels/4/challenges/1' target='_blank'>http://try.jquery.com/levels/4/challenges/1</a> and complete the fourth section."
]
},
{
"name": "Use jQuery for Styling",
"time": 30,
"video": "114591801",
"challengeNumber": 12,
"steps": [
"Finally, let's use jQuery to manipulate the way websites look by changing the CSS of elements.",
"Go to <a href='http://try.jquery.com/levels/5/challenges/1' target='_blank'>http://try.jquery.com/levels/5/challenges/1</a> and complete the fifth section."
]
},
{
"name": "Build a MadLibs Game",
"time": 60,
"video": "114591799",
"challengeNumber": 13,
"steps": [
"Now that we've built a foundation in jQuery, let's go back to Dash and do its last challenge.",
"If you aren't familiar with Mad Libs, they basically involve inserting random nouns, adjectives and verbs into stories. The stories that result are often hilarious.",
"Go to <a href='https://dash.generalassemb.ly/projects/mad-libs-1' target='_blank'>https://dash.generalassemb.ly/projects/mad-libs-1</a> and complete the fifth project."
]
},
{
"name": "Discover Chrome's DevTools",
"time": 90,
"video": "110752743",
"challengeNumber": 14,
"steps": [
"It's time to learn the most powerful tool your browser has - the Development Tools!",
"If you aren't already using Chrome, you'll want to download it here: <a href='http://www.google.com/chrome/' target='_blank'>http://www.google.com/chrome/</a>. While it's true that Firefox has a tool called Firebug that is very similar to Chrome's DevTools, we will use Chrome for this challenge.",
"Note that this course, jointly produced by Google and Code School, is technologically impressive, but occasionally buggy. If you encounter a bug, just ignore it and keep going.",
"Go to <a href='http://discover-devtools.codeschool.com' target='_blank'>http://discover-devtools.codeschool.com</a> and complete this short course."
]
},
{
"name": "Tackle jQuery Exercises",
"time": 60,
"video": "113173612",
"challengeNumber": 15,
"steps": [
"We've built some special jQuery challenges to help you reinforce your knowledge of this fundamental skill.",
"There are many correct ways to solve each of these exercises. After you complete the challenge, you can compare your solution with our solution by pressing the \"#solution-button\" button.",
"Go to <a href='http://freecodecamp.com/jquery-exercises' target='_blank'>http://freecodecamp.com/jquery-exercises</a> and complete the exercises."
]
},
{
"name": "Customize Bootstrap",
"time": 15,
"video": "110752741",
"challengeNumber": 16,
"steps": [
"Let's learn a little more about Twitter's responsive CSS framework, Bootstrap, and how we can add some custom themes to it.",
"Go to <a href='http://getbootstrap.com/components/' target='_blank'>http://getbootstrap.com/components/</a>",
"Right-click an area of the page that doesn't have any HTML elements on it, then choose 'view page source'.",
"Select all the text, then copy it.",
"Go to <a href='http://codepen.io/pen/' target='_blank'>http://codepen.io/pen/</a>",
"Paste the HTML you copied from GetBootStrap.com into the HTML field of CodePen.",
"Go to <a href='http://bootswatch.com/' target='_blank'>http://bootswatch.com/</a>",
"Decide which theme you want to use.",
"Click the down arrow next to the download button and choose 'bootstrap.css'.",
"Select all the text, then copy it.",
"Go back to CodePen and paste the CSS you copied from Bootswatch.com into the CSS field of CodePen.",
"Your Bootswatch CSS should now be applied to the HTML from the GetBootStrap page.",
"This page is currently using a two-column layout, with the main content on the left and additional navigation on the right. See if you can make it a one-column layout."
]
},
{
"name": "Inject Animation into CSS",
"time": 15,
"video": "110752740",
"challengeNumber": 17,
"steps": [
"You may have noticed some sites have cool animations. Actually, animating DOM elements is pretty straightforward if you use a CSS library called Animate.css.",
"Go to <a href='http://daneden.github.io/animate.css/' target='_blank'>http://daneden.github.io/animate.css/</a> and try out some of the CSS animations.",
"Go to <a href='http://codepen.io/ossia/pen/bGegt' target='_blank'>http://codepen.io/ossia/pen/bGegt</a>.",
"Press the \"Fork\" button. This will fork, meaning create a copy of, the CodePen.",
"Click the gear in the CSS column.",
"Click \"Add another resource\" and start typing \"animate.css\". Click on the dropdown results to autocomplete it.",
"Now that you have Animate.css enabled, use jQuery and the \"toggleClass\" method to add an animated class to all h1 elements when you click the \"Press Me\" button."
]
},
{
"name": "Learn Basic Computer Science",
"time": 120,
"video": "114628241",
"challengeNumber": 18,
"steps": [
"Stanford has an excellent free online Computer Science curriculum. This interactive course uses a modified version of JavaScript. It will cover a lot of concepts quickly.",
"Note that Harvard also has an excellent introduction to computer science course called CS50, but it takes more than 100 hours to complete, and doesn't use JavaScript.",
"Despite being completely self-paced, Stanford's CS101 course is broken up into weeks. Each of the following challenges will address one of those weeks.",
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z54/z1/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z54/z1/</a> and complete the first week's course work."
]
},
{
"name": "Learn Loops",
"time": 120,
"video": "114597348",
"challengeNumber": 19,
"steps": [
"Now let's tackle week 2 of Stanford's Intro to Computer Science course.",
"This will introduce us to loops, a fundamental feature of every programming language.",
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z100/a7a70ce6e4724c58862ee6007284face/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z100/a7a70ce6e4724c58862ee6007284face/</a> and complete Week 2."
]
},
{
"name": "Learn Computer Hardware",
"time": 120,
"video": "114597347",
"challengeNumber": 20,
"steps": [
"Week 3 of Stanford's Intro to Computer Science covers computer hardware and explains Moore's law of exponential growth in the price-performance of processors.",
"This challenge will also give you an understanding of how bits and bytes work.",
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z143/z101/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z143/z101/</a> and complete Week 3."
]
},
{
"name": "Learn Computer Networking",
"time": 120,
"video": "114604811",
"challengeNumber": 21,
"steps": [
"Now that you've learned about computer hardware, it's time to learn about the software that runs on top of it.",
"Particularly important, you will learn about networks and TCP/IP - the protocol that powers the internet.",
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z187/z144/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z187/z144/</a> and complete Week 4."
]
},
{
"name": "Learn Boolean Logic",
"time": 120,
"video": "114604812",
"challengeNumber": 22,
"steps": [
"Now we'll do some more table exercises and learn boolean logic.",
"We'll also learn the difference between digital data and analog data.",
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z208/z188/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z208/z188/</a> and complete Week 5."
]
},
{
"name": "Learn Computer Security",
"time": 120,
"video": "114604813",
"challengeNumber": 23,
"steps": [
"We're almost done with Stanford's Introduction to Computer Science course!",
"We'll learn about one of the most important inventions of the 20th century - spreadsheets.",
"We'll also learn about Computer Security and some of the more common vulnerabilities software systems have.",
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z229/z213/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z229/z213/</a> and complete Week 6, the final week of the course."
]
},
{
"name": "Build an Adventure Game",
"time": 60,
"video": "114604814",
"challengeNumber": 24,
"steps": [
"Now that you understand some Computer Science fundamentals, let's focus on programming JavaScript!",
"We're going to work through Codecademy's famous interactive JavaScript course.",
"This course will teach us some JavaScript fundamentals while guiding us through the process of building interesting web apps, all within Codecademy's learner-friendly environment!",
"Go to <a href='http://www.codecademy.com/courses/getting-started-v2/0/1' target='_blank'>http://www.codecademy.com/courses/getting-started-v2/0/1</a> and complete the section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-x9DnD/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-x9DnD/0/1</a>."
]
},
{
"name": "Build Rock Paper Scissors",
"time": 60,
"video": "114604815",
"challengeNumber": 25,
"steps": [
"Now we'll learn how JavaScript functions work, and use them to build a simple Rock Paper Scissors game.",
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-6LzGd/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-6LzGd/0/1</a> and complete the section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-Bthev-mskY8/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-Bthev-mskY8/0/1</a>."
]
},
{
"name": "Learn JavaScript For Loops",
"time": 60,
"video": "114614220",
"challengeNumber": 26,
"steps": [
"Let's learn more about the loops that make virtually all programs possible - the \"For Loop\" and \"While Loop\". First, we'll learn the For Loop.",
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-NhsaT/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-NhsaT/0/1web</a> and complete both the both For and While loop section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-XEDZA/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-XEDZA/0/1</a>."
]
},
{
"name": "Learn JavaScript While Loops",
"time": 60,
"video": "114612889",
"challengeNumber": 27,
"steps": [
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-ASGIv/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-ASGIv/0/1</a> and complete the section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-mrTNH-6VIZ9/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-mrTNH-6VIZ9/0/1</a>."
]
},
{
"name": "Learn Control Flow",
"time": 60,
"video": "114612888",
"challengeNumber": 28,
"steps": [
"Much of human reasoning can be broken down into what we call Boolean Logic. Lucky for us, computers can think the same way! Let's learn how to instruct our computers by writing \"If Statements\" and \"Else Statements\".",
"We'll also learn some advanced \"Control Flow\" principals, such as ways we can exit loops early.",
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-qDwp0/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-qDwp0/0/1</a> and complete the section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-ZA2rb/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-ZA2rb/0/1</a>."
]
},
{
"name": "Build a Contact List",
"time": 60,
"video": "114612887",
"challengeNumber": 29,
"steps": [
"Up to this point, you've been working mostly with strings and numbers. Now we're going to learn more complicated data structures, like \"Arrays\" and \"Objects\".",
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-9Sgpi/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-9Sgpi/0/1</a> and complete the section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-3bmfN/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-3bmfN/0/1</a>."
]
},
{
"name": "Build an Address Book",
"time": 60,
"video": "114612885",
"challengeNumber": 30,
"steps": [
"Let's learn more about objects.",
"Go to <a href='http://www.codecademy.com/courses/spencer-sandbox/0/1' target='_blank'>http://www.codecademy.com/courses/spencer-sandbox/0/1</a> and complete the section.",
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/building-an-address-book/0/1?curriculum_id=506324b3a7dffd00020bf661' target='_blank'>http://www.codecademy.com/courses/building-an-address-book/0/1?curriculum_id=506324b3a7dffd00020bf661</a>."
]
},
{
"name": "Build a Cash Register",
"time": 60,
"video": "114612882",
"challengeNumber": 31,
"steps": [
"In this final Codecademy section, we'll learn even more about JavaScript objects.",
"Go to <a href='http://www.codecademy.com/courses/objects-ii/0/1' target='_blank'>http://www.codecademy.com/courses/objects-ii/0/1</a> and complete this section.",
"Be sure to also complete the final section: <a href='http://www.codecademy.com/courses/close-the-super-makert/0/1' target='_blank'>http://www.codecademy.com/courses/close-the-super-makert/0/1</a>."
]
},
{
"name": "Get Help the Hacker Way",
"time": 30,
"video": "111500801",
"challengeNumber": 32,
"steps": [
"Watch the video to learn the RSAP (Read, Search, Ask, Post) methodology for getting help.",
"Try an intelligent Google query that involves JavaScript and filters for this year (since JavaScript changes).",
"Go to <a href='http://stackoverflow.com/' target='_blank'>http://stackoverflow.com/</a> and view the recent questions.",
"Go to <a href='http://webchat.freenode.net/' target='_blank'>http://webchat.freenode.net/</a> and create an IRC account.",
"Join the #LearnJavaScript chat room and introduce yourself as a Free Code Camp student.",
"Finally, we have a special chat room specifically for getting help with tools you learn through Free Code Camp Challenges. Go to <a href='https://gitter.im/FreeCodeCamp/Help' target='_blank'>https://gitter.im/FreeCodeCamp/Help</a>. Keep this chat open while you work on the remaining challenges.",
"Now you have several ways of getting help when you're stuck."
]
},
{
"name": "Learn Regular Expressions",
"time": 60,
"video": "112547802",
"challengeNumber": 33,
"steps": [
"You can use a Regular Expression, or \"Regex\", to select specific types of characters in text.",
"Check out <a href='http://www.regexr.com' target='_blank'>http://www.regexr.com</a>. It's a Regular Expression Sandbox.",
"Now go to <a href='http://www.regexone.com' target='_blank'>http://www.regexone.com</a> and complete the tutorial and exercises 1 - 6.",
"Note that you can click \"continue\" to move on to the next step as soon as all the tasks have green check marks beside them. You can often do this just by using the wildcard \"dot\" operator, but try to use the techniques that each lesson recommends."
]
},
{
"name": "Pair Program on Bonfires",
"time": 60,
"video": "119657641",
"challengeNumber": 34,
"steps": [
"OK, we're finally ready to start pair programming!",
"Pair Programming is where two people code together on the same computer. It is an efficient way to collaborate, and widely practiced at software companies. Pair Programming is one of the core concepts of \"Agile\" Software Development, which you will hear more about later.",
"Many people use Skype or Google Hangouts to pair program, but if you talk with professional software engineers, they will tell you that it's not really pair programming unless both people have the ability to use the keyboard and mouse.",
"The most popular tool for pair programming is Screen Hero. You can download Screen Hero for <a href='http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjowLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLnppcD9zb3VyY2U9d2ViIn0=' target='_blank'>Mac</a> or <a href='http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjoxLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLXNldHVwLmV4ZSJ9' target='_blank'>Windows</a>. Create your new user account from within the app.",
"We have a special chat room for people ready to pair program. Go to <a href='https://gitter.im/FreeCodeCamp/LetsPair' target='_blank'>https://gitter.im/FreeCodeCamp/LetsPair</a> and type \"Hello Pair Programmers!\"",
"If someone is available, they will be your \"pair\" - the person you pair programming with.",
"If no one gets back to you in the first few minutes, don't worry. There will be lots of opportunities to pair program in the future.",
"If someone does get back to you, private message them and ask for the email address they used to register Screen Hero.",
"Add them as a new contact in Screen Hero, then click the monitor-looking button to attempt to share your screen with them.",
"Once the Screen Hero session starts, your screen's margins will glow orange. You are now sharing your screen.",
"Your pair will have their own cursor, and will be able to type text on his or her and keyboard.",
"Now it's time to tackle our Bonfires.",
"Go to <a href='http://freecodecamp.com/bonfires' target='_blank'>http://freecodecamp.com/bonfires</a> and start working through our Bonfire challenges.",
"Once you you finish pair programming, end the session in Screen Hero session.",
"Congratulations! You have completed your first pair programming session.",
"Try to pair program with different campers until you've completed all the Bonfire challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!",
"You can complete Bonfire challenges while you continue to work through Free Code Camp's challenges. Take your time.",
"Mark this challenge as complete and move on."
]
},
{
"name": "Manage Source Code with Git",
"time": 30,
"video": "114635309",
"challengeNumber": 35,
"steps": [
"Revision Control Systems like Git ensure that, no matter how you experiment with your code, you can always roll back your app to a stable previous state.",
"Git is also a great way to share and contribute to open source software.",
"Go to <a href='https://www.codeschool.com/courses/try-git' target='_blank'>https://www.codeschool.com/courses/try-git</a> and complete this short interactive course."
]
},
{
"name": "Get Started with Node.js",
"time": 45,
"video": "114686471",
"challengeNumber": 36,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Now that we understand some Computer Science and JavaScript programming, you're ready to move on to Full-stack JavaScript!",
"The first step is to familiarize ourselves Node.js, the JavaScript-based web server that most full-stack JavaScript apps use.",
"When you're ready, go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/1/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/1/video/1</a> and complete the first chapter."
]
},
{
"name": "Try Node.js Events",
"time": 45,
"video": "114684206",
"challengeNumber": 37,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"One of the reasons Node.js is so fast is that it is \"evented.\" It processes events in an asynchronous manner.",
"As a result, Node.js relies on asynchronous callbacks.",
"We'll learn more about how events and callbacks work in this exciting Code School lesson.",
"Go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/2/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/2/video/1</a> and complete the section."
]
},
{
"name": "Try Node.js Streams",
"time": 45,
"video": "114684209",
"challengeNumber": 38,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"In this Code School lesson, we'll learn about streaming data back and forth between the client to the server.",
"We'll also learn about FS, or File System, an important Node.js module for streaming data.",
"Go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/3/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/3/video/1</a> and complete the section."
]
},
{
"name": "Learn how Node.js Modules Work",
"time": 45,
"video": "114684213",
"challengeNumber": 39,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"One of the most exciting features of Node.js is NPM - Node Package Manager",
"With NPM, you quickly install any of thousands of Node.js modules into your app, and it will automatically handle the other modules that each module dependends upon downstream.",
"In this lesson, we'll learn how to include these modules in our Node.js app by requiring them as variables.",
"Go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/4/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/4/video/1</a> and complete the section."
]
},
{
"name": "Start an Express.js Server",
"time": 45,
"video": "114684247",
"challengeNumber": 40,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"We'll complete Code School's Express.js course shortly after completing this course, but this challenge will give you a quick tour of the Express.js framework.",
"Go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/5/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/5/video/1</a> and complete the section."
]
},
{
"name": "Use Socket.io",
"time": 45,
"video": "114684530",
"challengeNumber": 41,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/6/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/6/video/1</a> and complete the section."
]
},
{
"name": "Use Redis to Persist Data",
"time": 45,
"video": "114684532",
"challengeNumber": 42,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Redis is a key-value store, which is a type of non-relational database. It's one of the fastest and easiest ways to persist data.",
"Even though we'll ultimately use MongoDB and other technologies to persist data, Redis is quite easy to learn and is still worth learning.",
"Go to <a href='http://campus.codeschool.com/courses/real-time-web-with-node-js/level/7/video/1' target='_blank'>http://campus.codeschool.com/courses/real-time-web-with-node-js/level/7/video/1</a> and complete the section."
]
},
{
"name": "Dive Deeper into Express.js",
"time": 45,
"video": "114684533",
"challengeNumber": 43,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Go to <a href='http://campus.codeschool.com/courses/building-blocks-of-express-js/level/1/video/1' target='_blank'>http://campus.codeschool.com/courses/building-blocks-of-express-js/level/1/video/1</a> and complete the section."
]
},
{
"name": "Setup Express.js Middleware",
"time": 45,
"video": "114684535",
"challengeNumber": 44,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Express.js makes extensive use of middleware - a stack of functions that run sequentially in response to a specific event.",
"Let's learn how to incorporate modules and middleware into our Express.js app.",
"Go to <a href='http://campus.codeschool.com/courses/building-blocks-of-express-js/level/2/video/1' target='_blank'>http://campus.codeschool.com/courses/building-blocks-of-express-js/level/2/video/1</a> and complete the section."
]
},
{
"name": "Take Advantage of Parameters",
"time": 45,
"video": "114684537",
"challengeNumber": 45,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Have you ever noticed a question mark in your browser's address bar, followed by a series of strings? Those are parameters. Parameters are an efficient way to pass information to the server between page loads.",
"We'll learn about parameters, along with a powerful Express.js feature called Dynamic Routing, in this exciting Code School lesson.",
"Go to <a href='http://campus.codeschool.com/courses/building-blocks-of-express-js/level/3/video/1' target='_blank'>http://campus.codeschool.com/courses/building-blocks-of-express-js/level/3/video/1</a> and complete the section."
]
},
{
"name": "Add the Body Parser",
"time": 45,
"video": "114684720",
"challengeNumber": 46,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"Now we'll add the Body Parser module to Express.js. Body Parser is a powerful middleware that helps with routing.",
"We'll also learn more about HTTP Requests, such as Post and Delete.",
"Go to <a href='http://campus.codeschool.com/courses/building-blocks-of-express-js/level/4/video/1' target='_blank'>http://campus.codeschool.com/courses/building-blocks-of-express-js/level/4/video/1</a> and complete the section."
]
},
{
"name": "Configure Routes in Express.js",
"time": 45,
"video": "114684724",
"challengeNumber": 47,
"steps": [
"Note that this Code School course is no longer free. We have free alternatives to this course <a href='/nodeschool-challenges' target='_blank'>here</a>.",
"For this last Code School Express.js challenge, we'll refactor our routes.",
"Go to <a href='http://campus.codeschool.com/courses/building-blocks-of-express-js/level/5/video/1' target='_blank'>http://campus.codeschool.com/courses/building-blocks-of-express-js/level/5/video/1</a> and complete the section."
]
},
{
"name": "Try MongoDB",
"time": 30,
"video": "114685061",
"challengeNumber": 48,
"steps": [
"MongoDB is a popular NoSQL (Not Only SQL) database used by many JavaScript apps.",
"Go to <a href='http://try.mongodb.org/' target='_blank'>http://try.mongodb.org/</a> and work through their interactive MongoDB tutorial."
]
},
{
"name": "Get Started with Angular.js",
"time": 45,
"video": "114684726",
"challengeNumber": 49,
"steps": [
"Code School has a short, free Angular.js course. This will give us a quick tour of Angular.js's mechanics and features.",
"In this course, we'll build a virtual shop entirely in Angular.js.",
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1</a> and complete the section."
]
},
{
"name": "Apply Angular.js Directives",
"time": 45,
"video": "114684727",
"challengeNumber": 50,
"steps": [
"Directives serve as markers in your HTML. When Angular.js compiles your HTML, it will can alter the behavior of DOM elements based on the directives you've used.",
"Let's learn how these powerful directives work, and how to use them to make your web apps more dynamic",
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/2/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/2/section/1/video/1</a> and complete the section."
]
},
{
"name": "Power Forms with Angular.js",
"time": 45,
"video": "114684729",
"challengeNumber": 51,
"steps": [
"One area where Angular.js really shines is its powerful web forms.",
"Learn how to create reactive Angular.js forms, including real-time form validation.",
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/3/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/3/section/1/video/1</a> and complete the section."
]
},
{
"name": "Customize Angular.js Directives",
"time": 45,
"video": "114685062",
"challengeNumber": 52,
"steps": [
"Now we'll learn how to modify existing Angular.js directives, and even build directives of your own.",
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/4/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/4/section/1/video/1</a> and complete the section."
]
},
{
"name": "Create Angular.js Services",
"time": 45,
"video": "114685060",
"challengeNumber": 53,
"steps": [
"Services are functions that you can use and reuse throughout your Angular.js app to get things done.",
"We'll learn how to use services in this final Code School Angular.js challenge.",
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/5/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/5/section/1/video/1</a> and complete the section."
]
}
]

View File

@ -1,3 +0,0 @@
[
]

File diff suppressed because it is too large Load Diff

294
seed_data/nonprofits.json Normal file
View File

@ -0,0 +1,294 @@
[
{
"id": "bd7157d8c441cbafaeb5bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Website",
"Donor Managment System",
"Inventory Management System",
"Volunteer Management System",
"Forms"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "We help the many less-fortunate Jewish families in our community, by providing them with nutritious food and energy to grow, learn, work, and give them hope for a better and brighter future.",
"websiteLink": "http://chasdeikaduri.org/",
"stakeholderName": "Jonathan Tebeka",
"stakeholderEmail": "jonathan@chasdeikaduri.org",
"name": "Chasdei Kaduri",
"endUser": "Clients, donors, and admin.",
"approvedDeliverables": [
"Website, Donor Management System, Inventory Management System, Volunteer Management System, Forms"
],
"projectDescription": "Campers will create a system will integrate the food inventory, donor and delivery driver management systems as well as replace the current application system with a custom form solution. System will include a more streamlined operations management, with user printable lists of inventory, drivers, and deliveries.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54c7e02f2c173c37015b2f36/604x309/00580a0567a4b3afda29d52b09e7e829/rQQ6zwq31Uya8ie9QHC-MlvfXxqftm9UPPe524JUhmwSEaZjQ7oL7U1tVoHLUj-gVUwM-7uzBGFsAXD_A_cx_JyAZP4Td-GMBJ-AebJNRAQP0m0v253eKMkURp63aG4%3Ds0-d-e1-ft.png",
"imageUrl": "http://chasdeikaduri.org/images/523455_516325865106850_1885515210_n.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "200"
},
{
"id": "bd7158d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Other"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "We connect simple technology with last mile communities to reduce poverty.",
"websiteLink": "http://kopernik.info/",
"stakeholderName": "Amber Gregory",
"stakeholderEmail": "amber.gregory@kopernik.info",
"name": "Kopernik",
"endUser": "Women in rural Indonesia.",
"approvedDeliverables": [
"Other"
],
"projectDescription": "Campers will create a Chrome browser extension to preserve sales data from a form, and upload in batches as the internet connection allows.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54d29f1e4c726fd765fa87ef/54d29f6388812dd367a243ab/x/018d9d3be5439870c56cccba5b3aa8bf/kopernik-logo-global.png",
"imageUrl": "http://kopernik.info/sites/default/files/updates/Presenting_the_low_carbon_t.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "100"
},
{
"id": "bd6274d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Other"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "No More Craptions seeks to improve upon automatic captioning on YouTube videos, by allowing users to edit captions to videos, even if they do not own the content.",
"websiteLink": "http://nomorecraptions.com/",
"stakeholderName": "Michael Lockrey",
"stakeholderEmail": "michael.lockrey@gmail.com",
"name": "No More Craptions",
"endUser": "Hearing impaired users, and those who want to correct poor captions.",
"approvedDeliverables": [
"Other"
],
"projectDescription": "Campers will create a full stack JavaScript solution to allow users to edit captions from YouTube videos.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54c1da1ba1fe2e325df5fc34/54c1dd31226b8111794d132f/x/b0402135d9ecce6d4ab45c4b5e5aeaa0/Turning-online-horse-manure-into-strawberry-jam---since-2009.png",
"imageUrl": "",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "200"
},
{
"id": "bd1326d9c245cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Website"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "We distribute biodegradable toothbrushes globally to children in need.",
"websiteLink": "http://www.operationbrush.org/",
"stakeholderName": "Dane Jonas",
"stakeholderEmail": "DaneJonas@operationbrush.org",
"name": "Operation Brush",
"endUser": "Donors",
"approvedDeliverables": [
"Website"
],
"projectDescription": "Campers will create a mobile responsive website for the organization, with donation capabilities.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54d9810307b159a4d9027aa2/54d981bfe5eb145560fbb769/x/cf7f318bfe4aee631b0d0eeef272225c/logo.png",
"imageUrl": "http://www.operationbrush.org/images/temp/hands1.png",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "100"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Community Management Tool"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "We are the largest roller derby league in the world with around 250 adults and 150 junior skater members plus 500+ volunteers.",
"websiteLink": "http://www.rosecityrollers.com/about/our-charities/",
"stakeholderName": "Charity Kuahiwinui",
"stakeholderEmail": "insurance@rosecityrollers.com",
"name": "Rose City Rollers",
"endUser": "Administrators, Coaches, and Volunteers",
"approvedDeliverables": [
"Community Management Tool"
],
"projectDescription": "Campers will create a volunteer management system with multi-user access and reporting capabilities.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54c1daf2d72d8eb868910b60/54c1dd4ecffcb09fc52b68a1/x/a8148f08769b449217e433bab8f39ddd/RCR-color.jpg",
"imageUrl": "http://www.rosecityrollers.com/wp-content/uploads/2015/01/BZ7_5923-X3-675x375.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "200"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Website"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "Save a Child's Heart provides urgently needed pediatric heart surgery and follow-up care for indigent children from developing countries",
"websiteLink": "http://www.saveachildsheart.com/global/young-leadership-program/",
"stakeholderName": "Shier Ziser",
"stakeholderEmail": "Shier_z@hotmail.com",
"name": "Save a Child's Heart",
"endUser": "Donors",
"approvedDeliverables": [
"Website"
],
"projectDescription": "Campers will create a single page fundraising website. In exchange for a donation, a user can customize a graphical 'heart' in someone's name or anonymously. The page will display all of the hearts on a 'wall of hearts.'",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/548b36629137780091a973cc/666x666/6c7a366ffb659649f6377d4a431687cd/country-logos-1-300dpi.jpg",
"imageUrl": "http://www.saveachildsheart.com/wp-content/uploads/2013/10/7.2.5_Internation_Photograohy_Exhibition.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "100"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Website"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "Savvy Cyber Kids enables youth to be empowered with technology by providing age appropriate resources and education.",
"websiteLink": "http://savvycyberkids.org/",
"stakeholderName": "Ben Halpert",
"stakeholderEmail": "info@savvycyberkids.org ",
"name": "Savvy Cyber Kids",
"endUser": "Donors",
"approvedDeliverables": [
"Website"
],
"projectDescription": "Campers will create a website where potential donors can view which schools already have the Savvy Cyber Kids books, and donate books to those schools that do not.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54ee3c7bf205562680177b59/218x190/1dc460de4edc9fdd4b481b24e93cfb23/logo.png",
"imageUrl": "http://www.privatewifi.com/wp-content/uploads/2014/10/Halpert.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "200"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Other"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "Transcendent Pathways ",
"websiteLink": "http://transcendentpathways.org/",
"stakeholderName": "Mark Ackerley",
"stakeholderEmail": "mackerley.music@gmail.com",
"name": "Transcendent Pathways",
"endUser": "Medical Facilities, Musicians",
"approvedDeliverables": [
"Other"
],
"projectDescription": "Campers will build a website where medical facilities can list music therapy time slots, and musicians can sign up to fill these slots.",
"logoUrl": "http://static1.squarespace.com/static/521b8957e4b024f66a58b214/t/521b8e9de4b093a8696eb9b8/1398718364447/?format=750w",
"imageUrl": "https://trello-attachments.s3.amazonaws.com/54fdb0328917ca64e9e8a79f/54fdc3b710f67caf6da14719/x/49fbe0012179bf254928f3f2a44810b4/Screen_2BShot_2B2013-08-26_2Bat_2B1.32.35_2BPM.png",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "200"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [
"Other"
],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "Timeraiser is a volunteer matching fair, a silent art auction, and a night out on the town. The big Timeraiser twist is rather than bid money on artwork, participants bid volunteer hours. ",
"websiteLink": "http://www.timeraiser.ca/",
"stakeholderName": "Stephanie McAllister",
"stakeholderEmail": "stephanie@timeraiser.ca",
"name": "Timeraiser",
"endUser": "Eventgoers",
"approvedDeliverables": [
"Other"
],
"projectDescription": "Campers will build a mobile responsive web form to allow Timeraiser eventgoers to select which nonprofit organizations they're interested in volunteering with. System will have Salesforce integration and reporting capabilities.",
"logoUrl": "http://www.timeraiser.ca/uploads/5/6/1/4/5614163/1277176.png?480",
"imageUrl": "http://www.timeraiser.ca/uploads/5/6/1/4/5614163/______________4571248_orig.png",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "100"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "string",
"websiteLink": "string",
"stakeholderName": "string",
"stakeholderEmail": "string",
"name": "string",
"endUser": "string",
"approvedDeliverables": [],
"projectDescription": "string",
"logoUrl": "string",
"imageUrl": "string",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "string"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "string",
"websiteLink": "string",
"stakeholderName": "string",
"stakeholderEmail": "string",
"name": "string",
"endUser": "string",
"approvedDeliverables": [],
"projectDescription": "string",
"logoUrl": "string",
"imageUrl": "string",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "string"
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"registeredNonprofit": true,
"requestedDeliverables": [],
"existingUserbase": true,
"acceptJavascript": true,
"agreeToTerms": true,
"whatDoesNonprofitDo": "string",
"websiteLink": "string",
"stakeholderName": "string",
"stakeholderEmail": "string",
"name": "string",
"endUser": "string",
"approvedDeliverables": [],
"projectDescription": "string",
"logoUrl": "string",
"imageUrl": "string",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": "string"
}
]

View File

@ -119,3 +119,16 @@ block content
legendColors: ["#cccccc", "#215f1e"],
legend: [1, 2, 3]
});
.row
.hidden-xs.col-sm-12.text-center
.row
h3.col-sm-6.text-center
.center-block.
#{longestStreak}
.center-block.
Longest Streak
h3.col-sm-6.text-center
.center-block.
#{currentStreak}
.center-block.
Current Streak

View File

@ -15,7 +15,7 @@ block content
script(src='/js/lib/codemirror/mode/javascript/javascript.js')
script(src='/js/lib/jailed/jailed.js')
script(src='/js/lib/bonfire/bonfireInit.js')
script(src="https://cdn.jsdelivr.net/ramda/0.10.0/ramda.min.js")
script(src='/js/lib/ramda/ramda.min.js')
.row
@ -73,9 +73,14 @@ block content
.col-xs-12
for sentence in details
p!= sentence
#MDN-links
h4 Here are some helpful links.
for link, index in MDNlinks
ul: li: a(href=""+link, target="_blank") !{MDNkeys[index]}
#less-info.btn.btn-primary.btn-block.btn-primary-ghost
span.ion-arrow-up-b
| Less information
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
#showAllButton.btn.btn-info.btn-big.btn-block Show all bonfires
br
@ -90,9 +95,10 @@ block content
var challengeSeed = !{JSON.stringify(challengeSeed)};
var passedBonfireHash = !{JSON.stringify(bonfireHash)};
var challengeName = !{JSON.stringify(name)};
var started = Math.floor(Date.now() / 1000);
var started = Math.floor(Date.now());
var _ = R;
var dashed = !{JSON.stringify(dashedName)};
.col-xs-12.col-sm-12.col-md-8
#mainEditorPanel
form.code
@ -111,7 +117,7 @@ block content
.text-center
.animated.zoomInDown.delay-half
span.completion-icon.ion-checkmark-circled.text-primary
- if (cc)
- if (user)
form.form-horizontal(novalidate='novalidate', name='completedWithForm')
.form-group.text-center
.col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2.animated.fadeIn
@ -126,14 +132,14 @@ block content
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-bonfire-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next bonfire (ctrl + enter)
- if (points && points > 2)
- if (user.progressTimestamps.length > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank")
i.fa.fa-twitter &thinsp;
= phrase
- else
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
#all-bonfires-dialog.modal(tabindex='-1')
#all-challenges-dialog.modal(tabindex='-1')
.modal-dialog.animated.fadeInUp.fast-animation
.modal-content
.modal-header.all-list-header Bonfires
@ -141,14 +147,7 @@ block content
.modal-body
include ../partials/bonfires
script.
$.ajax({
url: 'https://api-ssl.bitly.com/v3/shorten?access_token=75e7931a19befaafcf108021b6d597e554b2c5c3&longUrl=http%3A%2F%2Ffreecodecamp.com%2Fbonfires%2F' + dashed + '&format=txt'
})
.success(
function (data) {
console.log(data);
url = "https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=" + data + "&hashtags=LearnToCode, JavaScript";
$('.btn-twitter').attr('href', url);
var MDNlinks = !{JSON.stringify(MDNlinks)};
if (!MDNlinks.length) {
$('#MDN-links').addClass('collapse');
}
);

View File

@ -38,8 +38,8 @@ block content
span.ion-arrow-up-b
| Less information
br
- if (cc)
a.btn.btn-primary.btn-lg.btn-block#next-courseware-button
- if (user)
a.btn.btn-primary.btn-big.btn-block#next-courseware-button
| Go to my next challenge
br
| (ctrl + enter)
@ -49,6 +49,8 @@ block content
a.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
script.
var userLoggedIn = false;
.button-spacer
#showAllButton.btn.btn-info.btn-big.btn-block Show all challenges
br
ul#testSuite.list-group
br
@ -60,7 +62,8 @@ block content
var challengeName = !{JSON.stringify(name)};
var passedCoursewareName = challengeName;
var prodOrDev = !{JSON.stringify(environment)};
var started = Math.floor(Date.now() / 1000);
var challengeType = !{JSON.stringify(challengeType)};
var started = Math.floor(Date.now());
.col-xs-12.col-sm-12.col-md-5.col-lg-6
#mainEditorPanel
form.code
@ -82,3 +85,10 @@ block content
span.completion-icon.ion-checkmark-circled.text-primary
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
script(src="/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js")
#all-challenges-dialog.modal(tabindex='-1')
.modal-dialog.animated.fadeInUp.fast-animation
.modal-content
.modal-header.all-list-header Challenges
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
include ../partials/challenges

View File

@ -35,6 +35,7 @@ block content
span.ion-arrow-up-b
| Less information
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
#showAllButton.btn.btn-info.btn-big.btn-block Show all challenges
br
form.code
.form-group.codeMirrorView
@ -47,8 +48,10 @@ block content
var challengeSeed = !{JSON.stringify(challengeSeed)};
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
var challengeName = !{JSON.stringify(name)};
var challengeType = !{JSON.stringify(challengeType)};
var passedCoursewareName = challengeName;
var started = Math.floor(Date.now() / 1000);
var started = Math.floor(Date.now());
.col-xs-12.col-sm-12.col-md-8
#mainEditorPanel
form.code
@ -64,7 +67,7 @@ block content
.text-center
.animated.zoomInDown.delay-half
span.completion-icon.ion-checkmark-circled.text-primary
- if (cc)
- if (user)
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter)
- if (points && points > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{dashedName}&hashtags=LearnToCode, JavaScript" target="_blank")
@ -72,3 +75,10 @@ block content
= phrase
- else
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
#all-challenges-dialog.modal(tabindex='-1')
.modal-dialog.animated.fadeInUp.fast-animation
.modal-content
.modal-header.all-list-header Challenges
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
include ../partials/challenges

View File

@ -12,21 +12,24 @@ block content
.embed-responsive.embed-responsive-16by9
iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}')
br
- if (cc)
a.btn.btn-primary.btn-lg.btn-block#completed-courseware I've completed this challenge (ctrl + enter)
- if (user)
a.btn.btn-primary.btn-big.btn-block#completed-courseware I've completed this challenge (ctrl + enter)
script.
var userLoggedIn = true;
- else
a.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
a.btn.btn-big.signup-btn.btn-block(href='/login') Sign in so you can save your progress
script.
var userLoggedIn = false;
br
.button-spacer
#showAllButton.btn.btn-info.btn-big.btn-block Show all challenges
script(type="text/javascript").
var tests = !{JSON.stringify(tests)};
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
var challengeName = !{JSON.stringify(name)};
var passedCoursewareName = challengeName;
var started = Math.floor(Date.now() / 1000);
var started = Math.floor(Date.now());
var challengeType = !{JSON.stringify(challengeType)};
#complete-courseware-dialog.modal(tabindex='-1')
.modal-dialog.animated.zoomIn.fast-animation
.modal-content
@ -36,9 +39,9 @@ block content
.text-center
.animated.zoomInDown.delay-half
span.completion-icon.ion-checkmark-circled.text-primary
- if (cc)
- if (user)
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf) Go to my next challenge (ctrl + enter)
- if (points && points > 2)
- if (user.progressTimestamps.length > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{dashedName}&hashtags=LearnToCode, JavaScript" target="_blank")
i.fa.fa-twitter &thinsp;
= phrase
@ -46,10 +49,15 @@ block content
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
h1 #{name}
script.
var challengeName = !{JSON.stringify(name)};
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
$('body').on('keypress', function(e) {
if (e.ctrlKey && e.keyCode == 13) {
$('#complete-courseware-dialog').modal('show');
}
});
#all-challenges-dialog.modal(tabindex='-1')
.modal-dialog.animated.fadeInUp.fast-animation
.modal-content
.modal-header.all-list-header Challenges
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
include ../partials/challenges

View File

@ -0,0 +1,72 @@
extends ../layout-wide
block content
.row
.col-xs-12.col-sm-12.col-md-4.bonfire-top
h1.text-center= name
.well
h4
ol
for step in details
li!= step
.col-xs-12.col-sm-12.col-md-8
.embed-responsive.embed-responsive-16by9
iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}')
br
- if (user)
a.btn.btn-primary.btn-lg.btn-block#completed-zipline-or-basejump I've completed this challenge (ctrl + enter)
script.
var userLoggedIn = true;
- else
a.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
script.
var userLoggedIn = false;
br
script(type="text/javascript").
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
var challengeName = !{JSON.stringify(name)};
var passedCoursewareName = challengeName;
var started = Math.floor(Date.now());
var challengeType = !{JSON.stringify(challengeType)};
#complete-zipline-or-basejump-dialog.modal(tabindex='-1')
.modal-dialog.animated.zoomIn.fast-animation
.modal-content
.modal-header.challenge-list-header= compliment
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body(ng-controller="pairedWithController")
.text-center
.animated.zoomInDown.delay-half
span.completion-icon.ion-checkmark-circled.text-primary
- if (user)
form.form-horizontal(novalidate='novalidate', name='completedWithForm')
.form-group.text-center
.col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2.animated.fadeIn
// extra field to distract password tools like lastpass from injecting css into our username field
input.form-control(ng-show="false")
if (challengeType === 3)
input.form-control#public-url(name="codepenUrl", placeholder="http://codepen.io/your-pen-here", autofocus)
else
input.form-control#public-url(name="depoloymentUrl", placeholder="http://yourapp.com", autofocus)
input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project")
input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser")
.col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0")
alert(type='danger')
span.ion-close-circled
| Username not found
if (user)
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter)
- if (user.progressTimestamps.length > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank")
i.fa.fa-twitter &thinsp;
= phrase
- else
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
script.
$('body').on('keypress', function(e) {
if (e.ctrlKey && e.keyCode == 13) {
$('#complete-zipline-or-basejump-dialog').modal('show');
}
});

View File

@ -25,7 +25,7 @@ block content
a.btn.btn-cta.signup-btn(href="/login") Start learning to code (it's free)
br
br
a.btn.nonprofit-cta.btn-success(href="/nonprofits") I'm with a nonprofit and want help coding something
a.btn.nonprofit-cta.btn-success(href="/nonprofits") Get pro bono help for my nonprofit
.big-break
h2 Campers you'll hang out with:
.row

View File

@ -0,0 +1,12 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 We build solutions for nonprofits who are already serving a need. Are there people who already benefit from your services?
.spacer
.row
.col-xs-6
a.btn.btn-primary.btn-big.btn-block(href='/nonprofits/ok-with-javascript') Yes
.col-xs-6
a.btn.btn-warning.btn-big.btn-block(href='/nonprofits/other-solutions') No

View File

@ -0,0 +1,12 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Do you represent a nonprofit organization that is registered with your government?
.spacer
.row
.col-xs-6
a.btn.btn-primary.btn-big.btn-block(href='/nonprofits/are-there-people-that-are-already-benefiting-from-your-services') Yes
.col-xs-6
a.btn.btn-warning.btn-big.btn-block(href='/nonprofits/other-solutions') No

View File

@ -0,0 +1,83 @@
extends ../layout
block content
.jumbotron
.text-center
h2.nonprofit-landing.hug-top We'll code for your nonprofit, pro bono
.big-break
h2 Some of our success stories
.row
.col-xs-12.col-sm-12.col-md-4
img.img-responsive.testimonial-image.img-center(src="https://s3.amazonaws.com/freecodecamp/testimonial-jen.jpg", alt="@jenthebest's testimonial image")
.testimonial-copy Getting back on track with Free Code Camp and committing to a new career in 2015!
h3 - @jenbestyoga
.col-xs-12.col-sm-12.col-md-4
img.img-responsive.testimonial-image.img-center(src="https://s3.amazonaws.com/freecodecamp/testimonial-tate.jpg", alt="@TateThurston's testimonial image")
.testimonial-copy Just built my company's website with skills I've learned from Free Code Camp!
h3 - @TateThurston
.col-xs-12.col-sm-12.col-md-4
img.img-responsive.testimonial-image.img-center(src="https://s3.amazonaws.com/freecodecamp/testimonial-cynthia.jpg", alt="@cynthialanel's testimonial image")
.testimonial-copy I'm currently working through Free Code Camp to improve my JavaScript. The community is very welcoming!
h3 - @cynthialanel
.big-break
a.btn.btn-cta.signup-btn(href="/nonprofits/are-you-with-a-registered-nonprofit") Get pro bono help for my nonprofit
.big-break
h2 Our process
.row
.col-xs-12.col-sm-12.col-md-4
h3.nowrap Your idea
img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_portfolio.svg.gz', title='Get great references and connections to help you get a job')
p.landing-p You tell us how we can help you.
.col-xs-12.col-sm-12.col-md-4
h3.nowrap Our team
img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_nonprofits.svg.gz', title='Build a portfolio of apps for nonprofits')
p.landing-p We'll hand pick developers and a project manager.
.col-xs-12.col-sm-12.col-md-4
h3.nowrap Your solution
img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_connect.svg.gz', title='Help nonprofits')
p.landing-p Together we'll set milestones and complete your project.
.big-break
h2 Solutions we can help you build:
.text-center.negative-35
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-android-globe
h2.black-text Websites
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-card
h2.black-text Donation Systems
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-android-calendar
h2.black-text Volunteer Systems
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-ios-box
h2.black-text Inventory Systems
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-university
h2.black-text E-learning Platforms
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-ios-list
h2.black-text Web Forms
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-ios-people
h2.black-text Community Tools
.col-xs-12.col-sm-12.col-md-3
.landing-skill-icon.ion-settings
h2.black-text ...and other tools
br
br
.big-break
h2 Why you should join our community right now:
h3.col-xs-offset-0.col-sm-offset-1
ul.text-left
li.ion-code &thinsp; We're thousands of professionals, all learning to code together
li.ion-code &thinsp; We're building projects for dozens of nonprofits
li.ion-code &thinsp; Our community is 100% free and open source
li.ion-code &thinsp; You'll learn Full Stack JavaScript and become a Software Engineer
li.ion-code &thinsp; You'll work through our focused, interactive courses and tutorials
li.ion-code &thinsp; You'll learn to code at your own pace, in your browser or on your phone
li.ion-code &thinsp; You'll become qualified for thousands of jobs currently going unfilled
li.ion-code &thinsp; You can get help in real time from our community chat rooms and forum
li.ion-code &thinsp; We all share one common goal: to boost our careers with code
.big-break
a.btn.btn-cta.signup-btn(href="/nonprofits/are-you-with-a-registered-nonprofit") Get pro bono help for my nonprofit
script.
challengeName = 'Home'

View File

@ -0,0 +1,33 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 How can Free Code Camp help you?
.text-left.form-inline
h3.col-xs-12.col-sm-offset-5.checkbox-table
.col-xs-12
input.checkbox(type='checkbox', id='websites')
label.ion-android-globe &nbsp; Websites
.col-xs-12
input.checkbox(type='checkbox', id='donationSystems')
label.ion-card &nbsp; Donation Systems
.col-xs-12
input.checkbox(type='checkbox', id='volunteerSystems')
label.ion-android-calendar &nbsp; Volunteer Systems
.col-xs-12
input.checkbox(type='checkbox', id='inventorySystems')
label.ion-ios-box &nbsp; Inventory Systems
.col-xs-12
input.checkbox(type='checkbox', id='eLearningPlatforms')
label.ion-university &nbsp; E-learning Platforms
.col-xs-12
input.checkbox(type='checkbox', id='webForms')
label.ion-ios-list &nbsp; Web Forms
.col-xs-12
input.checkbox(type='checkbox', id='communityTools')
label.ion-ios-people &nbsp; Community Tools
.col-xs-12
input.checkbox(type='checkbox', id='otherTools')
label.ion-settings &nbsp; Other tools
button#next-step.btn.btn-primary.btn-big.btn-block(type='submit') I've selected all that apply and am ready to move on

View File

@ -0,0 +1,17 @@
extends ../layout
block content
.jumbotron
h1.hug-top.text-center Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Great! In exchange for our help, we ask only that you:
h3
ol
li Appoint one principal stakeholder to serve on behalf of your organization.
li Communicate with our campers on a regular basis, to answer questions and provide them with direction.
li Commit to using the solution that our campers build for your nonprofit.
.spacer
.row
.col-xs-6
a.btn.btn-primary.btn-big.btn-block(href='/nonprofits/how-can-free-code-camp-help-you') Sounds good!
.col-xs-6
a.btn.btn-warning.btn-big.btn-block(href='/nonprofits/other-solutions') This might not be for us.

View File

@ -0,0 +1,14 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Link us to the website, blog, or social media page that best represents your organization.
.spacer
form(role='form', method='GET', action="/nonprofits/tell-us-your-email/?" + existingParams)
input(type='hidden', name='_csrf', value=_csrf)
.formgroup
.input-group
input.form-control.big-text-field.field-responsive(type='text', name='link', autocomplete='off', maxlength='500', autofocus='')
span.input-group-btn
button.btn.btn-big.btn-primary.btn-responsive Submit

View File

@ -0,0 +1,12 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Our campers are learning to code using modern full stack JavaScript technologies like Node.js. We do not build or maintain Wordpress, Drupal, or other non-JavaScript based frameworks.
.spacer
.row
.col-xs-6
a.btn.btn-primary.btn-big.btn-block(href='/nonprofits/in-exchange-we-ask') Sounds good!
.col-xs-6
a.btn.btn-warning.btn-big.btn-block(href='/nonprofits/other-solutions') This might not be for us.

View File

@ -0,0 +1,5 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Here are some other solutions we recommend
.spacer

View File

@ -0,0 +1,14 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Please tell us your email
.spacer
form(role='form', method='GET', novalidate='novalidate', name='nonprofitForm', action="/nonprofits/tell-us-your-name/")
input(type='hidden', name='_csrf', value=_csrf)
.formgroup
.input-group
input.form-control.big-text-field.field-responsive(type='text', name='email', autocomplete='off', maxlength='500', autofocus='')
span.input-group-btn
button.btn.btn-big.btn-primary.btn-responsive Submit

View File

@ -0,0 +1,13 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Please tell us your name
.spacer
form(role='form', method='POST', novalidate='novalidate', name='nonprofitForm', action="/nonprofits/finish-application/")
.formgroup
.input-group
input.form-control.big-text-field.field-responsive(type='text', name='name', autocomplete='off', maxlength='140', autofocus='')
span.input-group-btn
button.btn.btn-big.btn-primary.btn-responsive Submit

View File

@ -0,0 +1,28 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 In 140 characters or less, what does your nonprofit do? For whom?
.spacer
form(role='form', method='GET', action="/nonprofits/link-us-to-your-website/")
input(type='hidden', name='_csrf', value=_csrf)
.formgroup
.input-group
input.form-control.big-text-field.field-responsive#what-does-the-nonprofit-do(type='text', maxlength='140', autofocus='', autocomplete='off', name='mission')
span.input-group-btn
button.btn.btn-big.btn-primary.btn-responsive(href='/nonprofits/link-us-to-your-website') Submit
.text-left
span#what-does-the-nonprofit-do-feedback
script.
var text_max = 140;
$('#what-does-the-nonprofit-do-feedback').html(text_max + ' characters remaining');
$('#what-does-the-nonprofit-do').keyup(function (e) {
if (e.which === 13 || e === 13) {
$('#submit-comment-to-comment').click();
}
var text_length = $('#what-does-the-nonprofit-do').val().length;
var text_remaining = text_max - text_length;
$('#what-does-the-nonprofit-do-feedback').html(text_remaining + ' characters remaining');
});

View File

@ -0,0 +1,6 @@
extends ../layout
block content
.jumbotron.text-center
h1.hug-top Nonprofit Sign Up
include ../partials/nonprofit-application-progress-bar
h2 Thank you for reaching out to us. Well get back with you before N of next week.

View File

@ -1,140 +0,0 @@
.panel.panel-info
.panel-heading.landing-panel-heading.text-center Our Team of Volunteer Camp Counselors
.panel-body
.landing-panel-body.text-center
.col-xs-12
script.
$(function () {
var parent = $("#shuffle");
var divs = parent.children();
while (divs.length) {
parent.append(divs.splice(Math.floor(Math.random() * divs.length), 1)[0]);
}
});
#shuffle
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Angelica Ferdinand
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/angelica-ferdinand.jpg' alt="Angelica Ferdinand's picture")
h4.text-nowrap Oakland, California
p.negative-10 "Computers have always lit my fire. I took a detour, but it's never too late to realize your dreams. If you love it, live it!"
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Ammar Shah
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/ammar-shah.jpg' alt="Ammar Shah's picture")
h4.text-nowrap Karachi, Pakistan
p.negative-10 "I code whenever I'm not sleeping or in school. Making computers obey me is a dream come true."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Branden Byers
h4.negative-10.text-nowrap Instructional Designer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/branden-byers.jpg' alt="Branden Byers picture")
h4.text-nowrap Madison, Wisconsin
p.negative-10 "Cookbook author and stay-at-home-dad. Started coding as a kid, got distracted, but now I'm back in full JavaScript force!"
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Michael Johnson
h4.negative-10.text-nowrap Nonprofit Coordinator
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/michael-johnson.jpeg' alt="Michael Johnson's picture")
h4.text-nowrap Washington, D.C.
p.negative-10 "Im a recent Harvard University graduate who took a pass on Wall Street to code for a cause, and help others do the same."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Berkeley Martinez
h4.negative-10.text-nowrap JavaScript Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/berkeley-martinez.jpg' alt="Berkeley Martinez's picture")
h4.text-nowrap San Francisco, California
p.negative-10 "Former mechanical engineer. Coding is pure creation. I can fly, but only once."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Mychael Zuniga
h4.negative-10.text-nowrap JavaScript Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/mychael-zuniga.jpg' alt="Mychael Zuniga's picture")
h4.text-nowrap San Diego, California
p.negative-10 "I'm a college student who turned to code as an avenue for creative expression. I love political science and economics."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Jeanette Casteñeta
h4.negative-10.text-nowrap Product Manager
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/jeanette-casteneta.jpg' alt="Jeanette Casteñeta's picture")
h4.text-nowrap San Francisco, California
p.negative-10 "Home-ec diva. I can envision a dress, then stitch it together. Now I'm learning how to do the same thing with code."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Darryl Dixon
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/darryl-dixon.jpg' alt="Darryl Dixon's picture")
h4.text-nowrap Newport News, Virginia
p.negative-10 "I'm a self-taught graphic designer. I'm learning web development here and want you to learn with me."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Kathy O'Driscoll
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/kathy-odriscoll.jpg' alt="Kathy O'Driscoll's picture")
h4.text-nowrap Los Angeles, California
p.negative-10 "Mother and grandmother. All my life I've dabbled in getting machines to do my bidding. Now it's becoming my career."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Ryan Malm
h4.negative-10.text-nowrap Visual Designer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/ryan-malm.jpg' alt="Ryan Malm's picture")
h4.text-nowrap Omaha, Nebraska
p.negative-10 "I love origami, piano, and playing minecraft with my kids. My JavaScript grows stronger every day."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Charles Watson
h4.negative-10.text-nowrap JavaScript Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/charles-watson.jpg' alt="Charles Watson's picture")
h4.text-nowrap Minneapolis, Minnesota
p.negative-10 "I skipped college. I build iOS apps. I love the obstacles and puzzles that coding presents me."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Quincy Larson
h4.negative-10.text-nowrap Instructional Designer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/quincy-larson.jpg' alt="Quincy Larson's picture")
h4.text-nowrap San Francisco, California
p.negative-10 "I worked as a school director in China before learning to code. It's clear that everyone can - and should - learn to code."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Mark Howard
h4.negative-10.text-nowrap Digital Marketer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/mark-howard.jpg' alt="Mark Howard's picture")
h4.text-nowrap San Diego, California
p.negative-10 "I enjoy helping people, at scale. Code is the best way to do that."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Nathan Leniz
h4.negative-10.text-nowrap JavaScript Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/nathan-leniz.jpg' alt="Nathan Leniz's picture")
h4.text-nowrap Seoul, South Korea
p.negative-10 "I learned to code for the games, and stayed for the algorithms."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Jason Rueckert
h4.negative-10.text-nowrap Live Content Manager
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/jason-rueckert.jpg' alt="Jason Rueckert's picture")
h4.text-nowrap Seattle, Washington
p.negative-10 "My high school job was testing basketball shoes for Nike. I learned code to work smarter, not harder. I have no thyroid."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Christopher Nguyen
h4.negative-10.text-nowrap QA Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/christopher-nguyen.jpg' alt="Christopher Nguyen's picture")
h4.text-nowrap Seattle, Washington
p.negative-10 "Morning Owl. Code is an equalizer. Barriers exist everywhere, but if you can say 'hello world', the world will say hello back."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Dominic Jones
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/dominic-jones.jpg' alt="Dominic Jones's picture")
h4.text-nowrap York, Pennsylvania
p.negative-10 "Born with Sickle Cell Anemia. Professional writer, working on becoming a professional code writer."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap James McShane
h4.negative-10.text-nowrap JavaScript Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/james-mcshane.jpg' alt="James McShane's picture")
h4.text-nowrap Minneapolis, Minnesota
p.negative-10 "I just bought our first house, ending a 10 year streak of moving each year. I've used code to solve problems since I was a child."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Ellie Adam
h4.negative-10.text-nowrap Visual Designer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/ellie-adam.jpg' alt="Eliie Adam's picture")
h4.text-nowrap Seattle, Washington
p.negative-10 "I photograph birds and flowers. I'm a designer who recently decided to learn coding and front end web developement."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Kamal Sharif
h4.negative-10.text-nowrap JavaScript Engineer
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/kamal-sharif.jpg' alt="Kamal Sharif's picture")
h4.text-nowrap Dhaka, Bangladesh
p.negative-10 "I build applications that help other people improve their own lives."
.col-xs-12.col-sm-12.col-md-12.col-lg-6.team-member
h3.negative-10.text-nowrap Patrick Ly
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/patrick-ly.jpg' alt="Patrick Ly's picture")
h4.text-nowrap Los Angeles, California
p.negative-10 "I'm a student and self-taught Hip Hop dancer. Just using the web isn't enough for me. I want to create and maintain web apps, too"

View File

@ -1,16 +0,0 @@
#blog
script.
(function() {
$.ajax({
url: '/api/blogger',
type: 'GET'
}).done(
function(data) {
var props = Object.keys(data);
for (var i = 0; i < props.length; i+=2) {
var blogger = document.createElement('div');
$(blogger).html('<h2><a href=' + data[props[i+1]] + '>' + data[props[i]] + '</a></h2></div>').appendTo($('#blog'))
}
}
);
})();

View File

@ -1,7 +1,10 @@
h3
ol#bonfireList
script(src='/js/lib/ramda/ramda.min.js')
script.
var getLinkedName = function getLinkedName(name) {
// ensure name is a string
name = name + '';
return name.toLowerCase().replace(/\s/g, '-');
}
$.ajax({
@ -10,14 +13,18 @@ h3
})
.success(
function(data) {
var docfrag = document.createDocumentFragment();
for (var i = 0; i < data.bonfireList.length; i++) {
var li = document.createElement('li');
var li = document.createElement("li");
var linkedName = getLinkedName(data.bonfireList[i].name);
if (R.contains(data.bonfireList[i]._id, data.completedList)) {
if (data.completedList.length > 0 && R.contains(data.bonfireList[i]._id, data.completedList)) {
$(li).html("<span class='sr-only'>completed</span><a href='/bonfires/" + linkedName + "'>" + data.bonfireList[i].name + "</a></li>");
$(li).addClass('strikethrough');
}
} else {
$(li).html("<a href='/bonfires/" + linkedName + "'>" + data.bonfireList[i].name + "</a></li>");
$(li).appendTo($('#bonfireList'));
}
docfrag.appendChild(li);
};
$('#bonfireList').append(docfrag);
});

View File

@ -1,8 +1,28 @@
h3
ol(start='0')
for challenge in challenges
li
a(href="/challenges/#{challenge.challengeNumber}", class="#{ (cc && cc[challenge.challengeNumber] > 0) ? 'strikethrough' : '' }") #{challenge.name}
| &thinsp; (#{challenge.time} mins)
ol#coursewareList
script(src='/js/lib/ramda/ramda.min.js')
script.
var getLinkedName = function getLinkedName(name) {
return name.toLowerCase().replace(/\s/g, '-');
}
$.ajax({
url: '/challenges/getCoursewareList',
type: 'GET'
})
.success(
function(data) {
var docfrag = document.createDocumentFragment();
for (var i = 0; i < data.coursewareList.length; i++) {
var li = document.createElement("li");
var linkedName = getLinkedName(data.coursewareList[i].name);
if (data.completedList.length > 0 && R.contains(data.coursewareList[i]._id, data.completedList)) {
$(li).html("<span class='sr-only'>completed</span><a href='/challenges/" + linkedName + "'>" + data.coursewareList[i].name + "</a></li>");
$(li).addClass('strikethrough');
} else {
$(li).html("<a href='/challenges/" + linkedName + "'>" + data.coursewareList[i].name + "</a></li>");
}
a.btn.btn-lg.btn-primary.btn-block(href="/done-with-first-100-hours", class="#{ ((points && points < 54) || (!points)) ? 'disabled' : '' }") I'm done with all the challenges!
docfrag.appendChild(li);
};
$('#coursewareList').append(docfrag);
});

View File

@ -1,23 +0,0 @@
h3
ol#coursewareList
script.
var getLinkedName = function getLinkedName(name) {
return name.toLowerCase().replace(/\s/g, '-');
}
$.ajax({
url: '/coursewares/getCoursewareList',
type: 'GET'
})
.success(
function(data) {
for (var i = 0; i < data.coursewareList.length; i++) {
var li = document.createElement('li');
var linkedName = getLinkedName(data.coursewareList[i].name);
if (R.contains(data.coursewareList[i]._id, data.completedList)) {
$(li).addClass('strikethrough');
}
$(li).html("<a href='/coursewares/" + linkedName + "'>" + data.coursewareList[i].name + "</a></li>");
$(li).appendTo($('#coursewareList'));
}
});

View File

@ -0,0 +1,39 @@
.spacer
.progress
.progress-bar(role='progressbar', aria-valuenow= (step * 10), aria-valuemin='0', aria-valuemax='100', style="width: #{step * 10}%;")
span.sr-only= step * 10
| % Complete
h3.gray-text.text-center Step #{step} of 9
script.
$('#story-url').on('keypress', function (e) {
if (e.which === 13 || e === 13) {
$('#preliminary-story-submit').click();
}
});
var preliminaryStorySubmit = function preliminaryStorySubmit() {
var storyURL = $('#story-url').val();
$('#preliminary-story-submit').attr('disabled', 'disabled');
$.post('/stories/preliminary',
{
data: {
url: storyURL
}
})
.fail(function (xhr, textStatus, errorThrown) {
$('#preliminary-story-submit').attr('disabled', false);
})
.done(function (data, textStatus, xhr) {
if (data.alreadyPosted) {
window.location = data.storyURL;
} else {
window.location = '/stories/submit/new-story?url=' +
encodeURIComponent(data.storyURL) +
'&title=' + encodeURIComponent(data.storyTitle) +
'&image=' + encodeURIComponent(data.storyImage) +
'&description=' + encodeURIComponent(data.storyMetaDescription);
}
});
}
$('#preliminary-story-submit').on('click', preliminaryStorySubmit);

View File

@ -1,13 +0,0 @@
#trello
script.
(function() {
$.ajax({
url: '/api/trello',
type: 'GET'
}).done(
function(data) {
var trello = document.createElement('div');
$(trello).html('<h3> We help ' + data.trello + ' nonprofits. <a href="https://trello.com/b/BA3xVpz9/nonprofit-projects">(view them)</a></h3>').prependTo($('#trello'))
}
);
})();

View File

@ -31,7 +31,8 @@ block content
.panel-body.text-center
img.img-responsive.img-center(src="https://s3.amazonaws.com/freecodecamp/about-trello.jpg" alt="a screen shot of Free Code Camp's nonprofit project Trello board showing several active projects")
h3 We launched #{daysRunning} days ago.
include ../partials/trello
h3 We help 20 nonprofits. &nbsp;
a(href='https://trello.com/b/BA3xVpz9/nonprofit-projects') (view them)
br
@ -49,7 +50,6 @@ block content
a(href=announcement[1])= announcement[0]
else
= announcement[0]
include ../partials/blogger
a.twitter-timeline(data-dnt='true', href='https://twitter.com/FreeCodeCamp', data-widget-id='560847186548621312') Tweets by @FreeCodeCamp
script.
!function (d, s, id) {
@ -76,22 +76,23 @@ block content
.col-xs-12.github-and-twitter-button-text
html.
<iframe src="http://ghbtns.com/github-btn.html?user=freecodecamp&repo=freecodecamp&type=watch&count=true&size=large" height="30" width="170" frameborder="0" scrolling="0" style="width:170px; height: 30px;" allowTransparency="true"></iframe>
include ../partials/about
.col-xs-12.col-sm-12.col-md-6
include ../partials/faq
#announcementModal.modal(tabindex='-1')
.modal-dialog
.modal-content
.modal-header.challenge-list-header New NodeSchool Challenges
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
h3.text-left Some of Code School's courses are no longer free. We're switching to NodeSchool.io for our Node.js and Express.js challenges.
a.btn.btn-lg.btn-info.btn-block(name='_csrf', value=_csrf, aria-hidden='true', href='/nodeschool-challenges') Take me to these new challenges
a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Thanks for the heads-up!
script.
$(document).ready(function() {
if (!localStorage || !localStorage.nodeSchoolAnnouncement) {
$('#announcementModal').modal('show');
localStorage.nodeSchoolAnnouncement = "true";
}
});
//#announcementModal.modal(tabindex='-1')
// .modal-dialog
// .modal-content
// .modal-header.challenge-list-header Camp-wide Meeting on Saturday at Noon EST
// a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
// .modal-body
// h3.text-left We'll live-stream some of Free Code Camp's new features, and campers will show what they're building. Live Saturday, March 28 at Noon EST on our &thinsp;
// a(href='http://twitch.tv/freecodecamp', target='_blank') Twitch.tv channel
// | .
// a.btn.btn-lg.btn-info.btn-block(name='_csrf', value=_csrf, aria-hidden='true', href='http://twitch.tv/freecodecamp', target='_blank') Take me to Twitch so I can follow Free Code Camp
// a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Thanks for the heads-up!
//script.
// $(document).ready(function() {
// if (!localStorage || !localStorage.campWideMeeting) {
// $('#announcementModal').modal('show');
// localStorage.campWideMeeting = "true";
// }
// });

View File

@ -56,7 +56,8 @@
sentinel--;
if (!sentinel) {
$('.comment-a-comment').on('click', 'a', function () {
if (!user) {
if (typeof user == "undefined" || !user) {
window.location.href = '/signin';
return;
}
$(this).unbind('click');

View File

@ -45,3 +45,11 @@
});
}
$('#preliminary-story-submit').on('click', preliminaryStorySubmit);
arr = $( "h3 input:checked" )
.map(function() {
return this.id;
})
.get()
.join('&');

View File

@ -56,7 +56,10 @@
$('#image-display').removeClass('hidden-element')
}
$('#reply-to-main-post').on('click', function() {
if (!user) return;
if (typeof user == "undefined" || !user) {
window.location.href = '/signin';
return;
}
$('#initial-comment-submit').removeClass('hidden-element');
$(this).unbind('click');
$('.comment-to-comment-formgroup').empty();