From 1f16b0f79a3f97c79087bb129b0ac6d5514cf1c2 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Wed, 4 Nov 2015 00:14:41 -0800 Subject: [PATCH 01/79] Fix story search not closing connections Now story search will use loopbacks mongo connection to do search --- server/boot/story.js | 70 ++++++++++++++++-------------- server/views/stories/news-nav.jade | 11 ++--- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/server/boot/story.js b/server/boot/story.js index 6c5bdea63a..8e00af3f16 100755 --- a/server/boot/story.js +++ b/server/boot/story.js @@ -2,15 +2,12 @@ var Rx = require('rx'), assign = require('object.assign'), sanitizeHtml = require('sanitize-html'), moment = require('moment'), - mongodb = require('mongodb'), debug = require('debug')('freecc:cntr:story'), utils = require('../utils'), observeMethod = require('../utils/rx').observeMethod, saveUser = require('../utils/rx').saveUser, saveInstance = require('../utils/rx').saveInstance, - MongoClient = mongodb.MongoClient, - validator = require('validator'), - secrets = require('../../config/secrets'); + validator = require('validator'); import { ifNoUser401, @@ -206,45 +203,54 @@ module.exports = function(app) { ); } - function getStories(req, res, next) { - MongoClient.connect(secrets.db, function(err, database) { - if (err) { - return next(err); + function getStories({ body: { search = '' } = {} }, res, next) { + if (!search || typeof search !== 'string') { + return res.sendStatus(404); + } + + const query = { + '$text': { + // protect against NoSQL injection + '$search': search.replace('$', '') } - database.collection('story').find({ - '$text': { - '$search': req.body.data ? req.body.data.searchValue : '' - } - }, { - headline: 1, - timePosted: 1, - link: 1, - description: 1, - rank: 1, - upVotes: 1, - author: 1, - image: 1, - storyLink: 1, - metaDescription: 1, + }; + + const fields = { + headline: 1, + timePosted: 1, + link: 1, + description: 1, + rank: 1, + upVotes: 1, + author: 1, + image: 1, + storyLink: 1, + metaDescription: 1, + textScore: { + $meta: 'textScore' + } + }; + + const options = { + sort: { textScore: { $meta: 'textScore' } - }, { - sort: { - textScore: { - $meta: 'textScore' - } - } - }).toArray(function(err, items) { + } + }; + + return app.dataSources.db.connector + .collection('story') + .find(query, fields, options) + .toArray(function(err, items) { if (err) { return next(err); } - if (items !== null && items.length !== 0) { + if (items && items.length !== 0) { return res.json(items); } return res.sendStatus(404); }); - }); } function upvote(req, res, next) { diff --git a/server/views/stories/news-nav.jade b/server/views/stories/news-nav.jade index 16631279c1..668e25952c 100644 --- a/server/views/stories/news-nav.jade +++ b/server/views/stories/news-nav.jade @@ -35,19 +35,14 @@ script. var getLinkedName = function getLinkedName(name) { return name.toLowerCase().replace(/\s/g, '-'); } - $.post('/stories/search', - { - data: { - searchValue: searchTerm - } - }) - .fail(function (xhr, textStatus, errorThrown) { + $.post('/stories/search', { search: searchTerm }) + .fail(function(xhr, textStatus, errorThrown) { $('#search-results').empty(); var div = document.createElement("div"); $(div).html("

No Results Found

"); $(div).appendTo($('#search-results')); }) - .done(function (data, textStatus, xhr) { + .done(function(data, textStatus, xhr) { $('#search-results').empty(); var spacer = document.createElement('div'); $(spacer).html("
"); From 02fa8970cabf71382aac509e872f4d769da09b4c Mon Sep 17 00:00:00 2001 From: Quincy Larson Date: Wed, 4 Nov 2015 00:45:42 -0800 Subject: [PATCH 02/79] remove mention of yeoman full stack generator --- seed/challenges/basejumps.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/seed/challenges/basejumps.json b/seed/challenges/basejumps.json index 850a8a2a88..c4171eb6f0 100644 --- a/seed/challenges/basejumps.json +++ b/seed/challenges/basejumps.json @@ -85,6 +85,12 @@ "A gif showing you how to create a new GitHub repository and push your code up to it.", "Create a new GitHub repository. Then copy its .git URL.
Return to c9.io's terminal and set your GitHub remote URL: git remote set-url origin followed by the URL you copied from GitHub.
Run git push origin master.
Now tab back to GitHub and refresh, and you'll see that your code is now on GitHub.", "https://github.com/new" + ], + [ + "http://i.imgur.com/Qn0K65B.gif", + "A gif showing you how to add add-ons to Heroku.", + "We will soon add instructions for getting Clementine running on Heroku. For now, develop your Basejumps right on c9.io.", + "" ] ], "type": "Waypoint", @@ -119,7 +125,6 @@ "Bonus User Story: As an unauthenticated or authenticated user, I can see and vote on everyone's polls.", "Bonus User Story: As an unauthenticated or authenticated user, I can see the results of polls in chart form. (This could be implemented using Chart.js or Google Charts.)", "Bonus User Story: As an authenticated user, if I don't like the options on a poll, I can create a new option.", - "If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: https://github.com/clnhll/guidetobasejumps.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", "If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project.

Click here then add your link to your tweet's text" ], @@ -151,8 +156,7 @@ "User Story: As an authenticated user, I can add myself to a bar to indicate I am going there tonight.", "User Story: As an authenticated user, I can remove myself from a bar if I no longer want to go there.", "Bonus User Story: As an unauthenticated user, when I login I should not have to search again.", - "Hint: Try using the Yelp API to find venues in the cities your users search for.", - "If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: https://github.com/clnhll/guidetobasejumps.", + "Hint: Try using the Yelp API to find venues in the cities your users search for. If you use Yelp's API, be sure to mention so in your app.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", "If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project.

Click here then add your link to your tweet's text" ], @@ -184,7 +188,6 @@ "User Story: As a user, I can add new stocks by their symbol name.", "User Story: As a user, I can remove stocks.", "Bonus User Story: As a user, I can see changes in real-time when any other user adds or removes a stock.", - "If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: https://github.com/clnhll/guidetobasejumps.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", "If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project.

Click here then add your link to your tweet's text" ], @@ -216,7 +219,6 @@ "User Story: As an authenticated user, I can add a new book.", "User Story: As an authenticated user, I can update my settings to store my full name, city, and state.", "Bonus User Story: As an authenticated user, I can propose a trade and wait for the other user to accept the trade.", - "If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: https://github.com/clnhll/guidetobasejumps.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", "If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project.

Click here then add your link to your tweet's text" ], @@ -251,7 +253,6 @@ "User Story: As an unauthenticated user, I can browse other users' walls of images.", "Bonus User Story: As an authenticated user, if I upload an image that is broken, it will be replaced by a placeholder image. (can use jQuery broken image detection)", "Hint: Masonry.js is a library that allows for Pinterest-style image grids.", - "If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: https://github.com/clnhll/guidetobasejumps.", "Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.", "If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project.

Click here then add your link to your tweet's text" ], From 59489fc07cc758172a882e2c50406322a7f92bbe Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Mon, 2 Nov 2015 14:17:50 -0800 Subject: [PATCH 03/79] chore(package): update dependencies http://greenkeeper.io/ --- package.json | 100 +++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index ef06329143..f3f08dfb99 100644 --- a/package.json +++ b/package.json @@ -26,46 +26,46 @@ }, "license": "(BSD-3-Clause AND CC-BY-SA-4.0)", "dependencies": { - "accepts": "~1.2.5", - "async": "~0.9.0", - "babel": "5.8.23", - "babel-core": "5.8.23", - "babel-eslint": "4.1.1", - "babel-loader": "5.2.2", + "accepts": "~1.3.0", + "async": "~1.5.0", + "babel": "6.0.15", + "babel-core": "6.0.17", + "babel-eslint": "4.1.3", + "babel-loader": "6.0.1", "bcrypt-nodejs": "~0.0.3", "body-parser": "^1.13.2", "chai-jquery": "~2.0.0", - "cheerio": "~0.18.0", + "cheerio": "~0.19.0", "classnames": "^2.1.2", "clockwork": "~0.1.1", - "compression": "~1.2.1", - "connect-mongo": "~0.7.0", - "cookie-parser": "~1.3.3", - "csso": "~1.3.11", + "compression": "~1.6.0", + "connect-mongo": "~0.8.2", + "cookie-parser": "~1.4.0", + "csso": "~1.4.1", "dateformat": "~1.0.11", - "debug": "~2.1.0", + "debug": "~2.2.0", "dedent": "^0.4.0", - "dotenv": "~0.4.0", - "errorhandler": "~1.3.0", + "dotenv": "~1.2.0", + "errorhandler": "~1.4.2", "es6-map": "^0.1.1", "eslint": "^1.1.0", "eslint-plugin-react": "^3.2.1", - "express": "~4.10.4", + "express": "~4.13.3", "express-flash": "~0.0.2", - "express-session": "~1.9.2", + "express-session": "~1.12.1", "express-state": "^1.2.0", - "express-validator": "~2.8.0", + "express-validator": "~2.18.0", "fetchr": "^0.5.12", - "font-awesome": "~4.3.0", - "forever": "~0.14.1", + "font-awesome": "~4.4.0", + "forever": "~0.15.1", "frameguard": "^0.2.2", - "github-api": "~0.7.0", - "gulp": "~3.8.8", - "gulp-eslint": "~0.9.0", - "gulp-inject": "~1.0.2", + "github-api": "~0.10.6", + "gulp": "~3.9.0", + "gulp-eslint": "~1.0.0", + "gulp-inject": "~3.0.0", "gulp-jsonlint": "^1.1.0", "gulp-less": "^3.0.3", - "gulp-minify-css": "~0.5.1", + "gulp-minify-css": "~1.2.1", "gulp-nodemon": "^2.0.3", "gulp-notify": "^2.2.0", "gulp-plumber": "^1.0.1", @@ -74,10 +74,10 @@ "gulp-rev-replace": "^0.4.2", "gulp-util": "^3.0.6", "gulp-webpack": "^1.5.0", - "helmet": "~0.9.0", - "helmet-csp": "^0.2.3", + "helmet": "~0.14.0", + "helmet-csp": "^0.3.0", "history": "^1.9.0", - "jade": "~1.8.0", + "jade": "~1.11.0", "json-loader": "^0.5.2", "less": "~2.5.1", "lodash": "^3.9.3", @@ -85,63 +85,63 @@ "loopback-boot": "^2.13.0", "loopback-component-passport": "https://github.com/FreeCodeCamp/loopback-component-passport.git#feature/flashfailure", "loopback-connector-mongodb": "^1.10.0", - "lusca": "~1.0.2", + "lusca": "~1.3.0", "method-override": "~2.3.0", "moment": "~2.10.2", "mongodb": "^2.0.33", - "morgan": "~1.5.0", + "morgan": "~1.6.1", "node-libs-browser": "^0.5.2", "node-slack": "0.0.7", "node-uuid": "^1.4.3", - "nodemailer": "~1.3.0", + "nodemailer": "~1.8.0", "normalize-url": "^1.3.1", - "object.assign": "^3.0.0", + "object.assign": "^4.0.3", "passport-facebook": "^2.0.0", - "passport-github": "^0.1.5", + "passport-github": "^1.0.0", "passport-google-oauth2": "^0.1.6", "passport-linkedin-oauth2": "^1.2.1", "passport-local": "^1.0.0", "passport-oauth": "^1.0.0", "passport-twitter": "^1.0.3", - "pmx": "^0.3.16", - "ramda": "~0.10.0", - "react": "^0.13.3", - "react-bootstrap": "~0.23.7", - "react-motion": "~0.1.0", + "pmx": "^0.5.5", + "ramda": "~0.18.0", + "react": "^0.14.2", + "react-bootstrap": "~0.27.3", + "react-motion": "~0.3.1", "react-router": "https://github.com/BerkeleyTrue/react-router.git#freecodecamp", "react-router-bootstrap": "^0.19.2", "react-vimeo": "^0.0.3", - "request": "~2.53.0", + "request": "~2.65.0", "rev-del": "^1.0.5", "rx": "^4.0.0", - "sanitize-html": "~1.6.1", + "sanitize-html": "~1.11.1", "sort-keys": "^1.1.1", "source-map-support": "^0.3.2", "store": "https://github.com/berkeleytrue/store.js.git#feature/noop-server", "thundercats": "^3.0.0", "thundercats-react": "^0.3.0", - "twit": "~1.1.20", - "uglify-js": "~2.4.15", + "twit": "~2.1.1", + "uglify-js": "~2.5.0", "url-regex": "^3.0.0", - "validator": "^3.22.1", + "validator": "^4.2.1", "webpack": "^1.9.12", "xss-filters": "^1.2.6", "yui": "~3.18.1" }, "devDependencies": { - "blessed": "~0.0.37", + "blessed": "~0.1.81", "bower-main-files": "~0.0.4", - "browser-sync": "~1.8.1", - "browserify": "^10.2.4", - "chai": "~1.10.0", + "browser-sync": "~2.9.11", + "browserify": "^12.0.1", + "chai": "~3.4.0", "envify": "^3.4.0", - "istanbul": "^0.3.15", + "istanbul": "^0.4.0", "jsonlint": "^1.6.2", - "loopback-explorer": "^1.7.2", + "loopback-explorer": "^2.0.2", "loopback-testing": "^1.1.0", - "mocha": "~2.0.1", + "mocha": "~2.3.3", "multiline": "~1.0.1", - "supertest": "~0.15.0", + "supertest": "~1.1.0", "tap-nyan": "0.0.2", "tape": "^4.2.2", "vinyl-source-stream": "^1.1.0" From f9f89edddf687d91f23ff658558947405ee6cdfa Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Wed, 4 Nov 2015 00:46:45 -0800 Subject: [PATCH 04/79] Revert to old babel. Babel is broken --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f3f08dfb99..75db855279 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,10 @@ "dependencies": { "accepts": "~1.3.0", "async": "~1.5.0", - "babel": "6.0.15", - "babel-core": "6.0.17", + "babel": "5.8.29", + "babel-core": "5.8.33", "babel-eslint": "4.1.3", - "babel-loader": "6.0.1", + "babel-loader": "5.3.3", "bcrypt-nodejs": "~0.0.3", "body-parser": "^1.13.2", "chai-jquery": "~2.0.0", @@ -119,7 +119,7 @@ "source-map-support": "^0.3.2", "store": "https://github.com/berkeleytrue/store.js.git#feature/noop-server", "thundercats": "^3.0.0", - "thundercats-react": "^0.3.0", + "thundercats-react": "^0.4.0", "twit": "~2.1.1", "uglify-js": "~2.5.0", "url-regex": "^3.0.0", From 59bd917a2c2408bcd7ac308e596ae2cef3d59e6a Mon Sep 17 00:00:00 2001 From: Arsen Melikyan Date: Sun, 25 Oct 2015 12:30:44 +0400 Subject: [PATCH 05/79] save bonfire solution as a gist and fix search issue button query string --- client/main.js | 55 ++++++++++++++++++++++- server/middlewares/csp.js | 3 +- server/views/coursewares/showBonfire.jade | 6 +++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/client/main.js b/client/main.js index 6f147abcf7..44e8c21d73 100644 --- a/client/main.js +++ b/client/main.js @@ -208,13 +208,66 @@ $(document).ready(function() { $('#search-issue').unbind('click'); $('#search-issue').on('click', function() { - var queryIssue = window.location.href.toString(); + var queryIssue = window.location.href.toString().split('#?')[0]; window.open('https://github.com/FreeCodeCamp/FreeCodeCamp/issues?q=' + 'is:issue is:all ' + (challenge_Name || challengeName) + ' OR ' + queryIssue.substr(queryIssue.lastIndexOf('challenges/') + 11) .replace('/', ''), '_blank'); }); + $('#gist-share').unbind('click'); + $('#gist-share').on('click', function() { + var gistWindow = window.open('', '_blank'); + + $('#gist-share') + .attr('disabled', 'true') + .removeClass('btn-danger') + .addClass('btn-warning disabled'); + + function createCORSRequest(method, url) { + var xhr = new XMLHttpRequest(); + if ('withCredentials' in xhr) { + xhr.open(method, url, true); + } else if (typeof XDomainRequest !== 'undefined') { + xhr = new XDomainRequest(); + xhr.open(method, url); + } else { + xhr = null; + } + xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8'); + return xhr; + } + + var request = createCORSRequest('post', 'https://api.github.com/gists'); + if (request) { + request.onload = function() { + if (request.readyState === 4 && + request.status === 201 && + request.statusText === 'Created') { + gistWindow.location.href = JSON.parse(request.responseText)['html_url']; + } + }; + var data = { + description: (challenge_Name || challengeName), + public: true, + files: {} + }, + queryIssue = window.location.href.toString().split('#?')[0], + filename = queryIssue + .substr(queryIssue.lastIndexOf('challenges/') + 11) + .replace('/', '') + '.js'; + data['files'][filename] = { + content: '// ' + data.description + '\n' + + (username ? '// Author: @' + username + '\n' : '') + + '// Challenge: ' + queryIssue + '\n' + + '// Learn to Code at Free Code Camp (www.freecodecamp.com)' + + '\n\n' + editor.getValue().trim() + }; + + request.send(JSON.stringify(data)); + } + }); + $('#help-ive-found-a-bug-wiki-article').unbind('click'); $('#help-ive-found-a-bug-wiki-article').on('click', function() { window.open("https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help-I've-Found-a-Bug", '_blank'); diff --git a/server/middlewares/csp.js b/server/middlewares/csp.js index 24e1e848cf..391f9bb450 100644 --- a/server/middlewares/csp.js +++ b/server/middlewares/csp.js @@ -48,7 +48,8 @@ const trusted = [ 'http://hn.inspectlet.com/', '*.googleapis.com', '*.gstatic.com', - 'https://hn.inspectlet.com/' + 'https://hn.inspectlet.com/', + 'https://*.github.com' ]; export default function csp() { diff --git a/server/views/coursewares/showBonfire.jade b/server/views/coursewares/showBonfire.jade index 5a2f6c0a11..7ca4a6c74f 100644 --- a/server/views/coursewares/showBonfire.jade +++ b/server/views/coursewares/showBonfire.jade @@ -80,6 +80,10 @@ block content var dashedName = !{JSON.stringify(dashedName)}; var _ = R; var dashed = !{JSON.stringify(dashedName)}; + var username; + if (user) + script(type="text/javascript"). + username = !{JSON.stringify(user.username)}; .col-md-8.col-lg-9 .editorScrollDiv(style = "overflow-y: auto; overflow-x: hidden;") @@ -103,12 +107,14 @@ block content .row if (user) #submit-challenge.animated.fadeIn.btn.btn-lg.btn-primary.btn-block Submit and go to my next challenge (ctrl + enter) + a.animated.fadeIn.btn.btn-lg.btn-danger.btn-block#gist-share Share your solution as a GitHub gist if (user.progressTimestamps.length > 2) a.btn.btn-lg.btn-block.btn-twitter(target="_blank", href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{dashedName}&hashtags=LearnToCode, JavaScript", onclick="ga('send', 'event', 'twitter', 'share', 'challenge completion share');") i.fa.fa-twitter   = phrase else #next-challenge.btn.btn-lg.btn-primary.btn-block Go to my next challenge (ctrl + enter) + a.btn.btn-lg.btn-danger.btn-block#gist-share Share your solution as a GitHub gist #reset-modal.modal(tabindex='-1') .modal-dialog.animated.fadeInUp.fast-animation .modal-content From bf403387196191abc7f48c323623c2c5a56857d1 Mon Sep 17 00:00:00 2001 From: Arsen Melikyan Date: Wed, 4 Nov 2015 15:37:37 +0400 Subject: [PATCH 06/79] improve gist's title --- client/main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/main.js b/client/main.js index 44e8c21d73..c8f08cb910 100644 --- a/client/main.js +++ b/client/main.js @@ -248,7 +248,8 @@ $(document).ready(function() { } }; var data = { - description: (challenge_Name || challengeName), + description: (username ? 'http://www.freecodecamp.com/' + username + + ' \'s s' : 'S') + 'olution for ' + (challenge_Name || challengeName), public: true, files: {} }, @@ -257,7 +258,7 @@ $(document).ready(function() { .substr(queryIssue.lastIndexOf('challenges/') + 11) .replace('/', '') + '.js'; data['files'][filename] = { - content: '// ' + data.description + '\n' + + content: '// ' + (challenge_Name || challengeName) + '\n' + (username ? '// Author: @' + username + '\n' : '') + '// Challenge: ' + queryIssue + '\n' + '// Learn to Code at Free Code Camp (www.freecodecamp.com)' + From 8a5e12f6f3dc8d7952e94df9a7079ef86d47ad62 Mon Sep 17 00:00:00 2001 From: Arsen Melikyan Date: Sun, 1 Nov 2015 16:58:28 +0400 Subject: [PATCH 07/79] find users news by typing their usernames in search box and fix FF CSS issue --- client/less/main.less | 3 ++- server/boot/story.js | 22 ++++++++++++++++++++++ server/views/stories/news-nav.jade | 9 +++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/client/less/main.less b/client/less/main.less index 8d3ceb2ad1..64b89d0f48 100644 --- a/client/less/main.less +++ b/client/less/main.less @@ -814,7 +814,8 @@ iframe.iphone { .news-box-search { @media (min-width: 768px) { - margin-top: -50px; + margin-top: -30px; + padding-bottom: 20px; } @media (max-width: 767px) { padding: 5px; diff --git a/server/boot/story.js b/server/boot/story.js index 8e00af3f16..58a4c53fc4 100755 --- a/server/boot/story.js +++ b/server/boot/story.js @@ -62,6 +62,7 @@ module.exports = function(app) { var findStoryById = observeMethod(Story, 'findById'); var countStories = observeMethod(Story, 'count'); + router.post('/news/userstories', userStories); router.get('/news/hot', hotJSON); router.get('/stories/hotStories', hotJSON); router.get( @@ -104,6 +105,27 @@ module.exports = function(app) { ); } + function userStories({ body: { search = '' } = {} }, res, next) { + if (!search || typeof search !== 'string') { + return res.sendStatus(404); + } + + return app.dataSources.db.connector + .collection('story') + .find({ + 'author.username': search.replace('$', '') + }) + .toArray(function(err, items) { + if (err) { + return next(err); + } + if (items && items.length !== 0) { + return res.json(items.sort(sortByRank)); + } + return res.sendStatus(404); + }); + } + function hot(req, res) { return res.render('stories/index', { title: 'Top Stories on Camper News', diff --git a/server/views/stories/news-nav.jade b/server/views/stories/news-nav.jade index 668e25952c..2fdd18582f 100644 --- a/server/views/stories/news-nav.jade +++ b/server/views/stories/news-nav.jade @@ -31,11 +31,16 @@ script. }); function executeSearch() { $('#stories').empty(); - var searchTerm = $('#searchArea').val(); + var searchTerm = $('#searchArea').val(), + url = '/stories/search'; + if (searchTerm.match(/^\@\w+$/)) { + url = '/news/userstories'; + searchTerm = searchTerm.match(/^\@\w+$/)[0].split('@')[1]; + } var getLinkedName = function getLinkedName(name) { return name.toLowerCase().replace(/\s/g, '-'); } - $.post('/stories/search', { search: searchTerm }) + $.post(url, { search: searchTerm }) .fail(function(xhr, textStatus, errorThrown) { $('#search-results').empty(); var div = document.createElement("div"); From c38841c5af666f1cf87c943cb2f308c4c244ac37 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Wed, 4 Nov 2015 11:04:54 -0800 Subject: [PATCH 08/79] Fix Code Editor Changes Creating Duplicate History Entries Closes #4167 --- client/commonFramework.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/commonFramework.js b/client/commonFramework.js index 20ba4b40e1..ef3427928c 100644 --- a/client/commonFramework.js +++ b/client/commonFramework.js @@ -136,8 +136,16 @@ common.codeUri = (function(common, encode, decode, location, history) { if (!codeUri.enabled) { return null; } - location.hash = '?solution=' + - codeUri.encode(encodeFcc(solution)); + if (history && typeof history.replaceState === 'function') { + history.replaceState( + history.state, + null, + '?solution=' + codeUri.encode(encodeFcc(solution)) + ); + } else { + location.hash = '?solution=' + + codeUri.encode(encodeFcc(solution)); + } return solution; }, From 79fd8e0bf899ee445cfcf168249aef050ee2d900 Mon Sep 17 00:00:00 2001 From: Rex Schrader Date: Wed, 4 Nov 2015 11:28:28 -0800 Subject: [PATCH 09/79] Fixes 4160 - Missing Semicolon on Use an ID Attribute --- seed/challenges/html5-and-css.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seed/challenges/html5-and-css.json b/seed/challenges/html5-and-css.json index 6ceb796a9c..2cd296e3c6 100644 --- a/seed/challenges/html5-and-css.json +++ b/seed/challenges/html5-and-css.json @@ -2603,8 +2603,9 @@ " .smaller-image {", " width: 100px;", " }", + "", " .gray-background {", - " background-color: gray", + " background-color: gray;", " }", "", "", From 8f3c3e39723dbcf58787f16af4c2b2c5125a650c Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Wed, 4 Nov 2015 12:37:25 -0800 Subject: [PATCH 10/79] Fix most lint issues --- client/commonFramework.js | 332 ++++++++++++++++++++++++++++++++++---- client/iFrameScripts.js | 3 + client/plugin.js | 2 +- 3 files changed, 303 insertions(+), 34 deletions(-) diff --git a/client/commonFramework.js b/client/commonFramework.js index 20ba4b40e1..21702f8adf 100644 --- a/client/commonFramework.js +++ b/client/commonFramework.js @@ -476,15 +476,22 @@ var editor = (function(CodeMirror, emmetCodeMirror, common) { var tests = tests || []; -var libraryIncludes = "" + - "" + - "" + - "" + - "" + - "" + - "" + - '' + - ''; +var libraryIncludes = + "' + + "" + + "" + + "" + + "" + + "" + + "" + + '' + + ''; var editorValueForIFrame; var iFrameScript = ""; @@ -498,9 +505,13 @@ function workerError(error) { housing.prepend( '
' + - error.replace(/j\$/gi, '$').replace(/jdocument/gi, 'document').replace(/jjQuery/gi, 'jQuery') + + error + .replace(/j\$/gi, '$') + .replace(/jdocument/gi, 'document') + .replace(/jjQuery/gi, 'jQuery') + '
' ); + display.hide().fadeIn(function() { setTimeout(function() { display.fadeOut(function() { @@ -533,21 +544,269 @@ function safeHTMLRun(test) { .split(/\<\s?\/\s?script\s?\>/gi)[0]; // add feuxQuery - s = 'var document = \"\"; var $ = function() {return(new function() {this.add=function() {return(this);};this.addBack=function() {return(this);};this.addClass=function() {return(this);};this.after=function() {return(this);};this.ajaxComplete=function() {return(this);};this.ajaxError=function() {return(this);};this.ajaxSend=function() {return(this);};this.ajaxStart=function() {return(this);};this.ajaxStop=function() {return(this);};this.ajaxSuccess=function() {return(this);};this.andSelf=function() {return(this);};this.animate=function() {return(this);};this.append=function() {return(this);};this.appendTo=function() {return(this);};this.attr=function() {return(this);};this.before=function() {return(this);};this.bind=function() {return(this);};this.blur=function() {return(this);};this.callbacksadd=function() {return(this);};this.callbacksdisable=function() {return(this);};this.callbacksdisabled=function() {return(this);};this.callbacksempty=function() {return(this);};this.callbacksfire=function() {return(this);};this.callbacksfired=function() {return(this);};this.callbacksfireWith=function() {return(this);};this.callbackshas=function() {return(this);};this.callbackslock=function() {return(this);};this.callbackslocked=function() {return(this);};this.callbacksremove=function() {return(this);};this.change=function() {return(this);};this.children=function() {return(this);};this.clearQueue=function() {return(this);};this.click=function() {return(this);};this.clone=function() {return(this);};this.closest=function() {return(this);};this.contents=function() {return(this);};this.context=function() {return(this);};this.css=function() {return(this);};this.data=function() {return(this);};this.dblclick=function() {return(this);};this.delay=function() {return(this);};this.delegate=function() {return(this);};this.dequeue=function() {return(this);};this.detach=function() {return(this);};this.die=function() {return(this);};this.each=function() {return(this);};this.empty=function() {return(this);};this.end=function() {return(this);};this.eq=function() {return(this);};this.error=function() {return(this);};this.fadeIn=function() {return(this);};this.fadeOut=function() {return(this);};this.fadeTo=function() {return(this);};this.fadeToggle=function() {return(this);};this.filter=function() {return(this);};this.find=function() {return(this);};this.finish=function() {return(this);};this.first=function() {return(this);};this.focus=function() {return(this);};this.focusin=function() {return(this);};this.focusout=function() {return(this);};this.get=function() {return(this);};this.has=function() {return(this);};this.hasClass=function() {return(this);};this.height=function() {return(this);};this.hide=function() {return(this);};this.hover=function() {return(this);};this.html=function() {return(this);};this.index=function() {return(this);};this.innerHeight=function() {return(this);};this.innerWidth=function() {return(this);};this.insertAfter=function() {return(this);};this.insertBefore=function() {return(this);};this.is=function() {return(this);};this.jQuery=function() {return(this);};this.jquery=function() {return(this);};this.keydown=function() {return(this);};this.keypress=function() {return(this);};this.keyup=function() {return(this);};this.last=function() {return(this);};this.length=function() {return(this);};this.live=function() {return(this);};this.load=function() {return(this);};this.load=function() {return(this);};this.map=function() {return(this);};this.mousedown=function() {return(this);};this.mouseenter=function() {return(this);};this.mouseleave=function() {return(this);};this.mousemove=function() {return(this);};this.mouseout=function() {return(this);};this.mouseover=function() {return(this);};this.mouseup=function() {return(this);};this.next=function() {return(this);};this.nextAll=function() {return(this);};this.nextUntil=function() {return(this);};this.not=function() {return(this);};this.off=function() {return(this);};this.offset=function() {return(this);};this.offsetParent=function() {return(this);};this.on=function() {return(this);};this.one=function() {return(this);};this.outerHeight=function() {return(this);};this.outerWidth=function() {return(this);};this.parent=function() {return(this);};this.parents=function() {return(this);};this.parentsUntil=function() {return(this);};this.position=function() {return(this);};this.prepend=function() {return(this);};this.prependTo=function() {return(this);};this.prev=function() {return(this);};this.prevAll=function() {return(this);};this.prevUntil=function() {return(this);};this.promise=function() {return(this);};this.prop=function() {return(this);};this.pushStack=function() {return(this);};this.queue=function() {return(this);};this.ready=function() {return(this);};this.remove=function() {return(this);};this.removeAttr=function() {return(this);};this.removeClass=function() {return(this);};this.removeData=function() {return(this);};this.removeProp=function() {return(this);};this.replaceAll=function() {return(this);};this.replaceWith=function() {return(this);};this.resize=function() {return(this);};this.scroll=function() {return(this);};this.scrollLeft=function() {return(this);};this.scrollTop=function() {return(this);};this.select=function() {return(this);};this.selector=function() {return(this);};this.serialize=function() {return(this);};this.serializeArray=function() {return(this);};this.show=function() {return(this);};this.siblings=function() {return(this);};this.size=function() {return(this);};this.slice=function() {return(this);};this.slideDown=function() {return(this);};this.slideToggle=function() {return(this);};this.slideUp=function() {return(this);};this.stop=function() {return(this);};this.submit=function() {return(this);};this.text=function() {return(this);};this.toArray=function() {return(this);};this.toggle=function() {return(this);};this.toggle=function() {return(this);};this.toggleClass=function() {return(this);};this.trigger=function() {return(this);};this.triggerHandler=function() {return(this);};this.unbind=function() {return(this);};this.undelegate=function() {return(this);};this.unload=function() {return(this);};this.unwrap=function() {return(this);};this.val=function() {return(this);};this.width=function() {return(this);};this.wrap=function() {return(this);};this.wrapAll=function() {return(this);};this.wrapInner=function() {return(this);}});};$.ajax=function() {return($);};$.ajaxPrefilter=function() {return($);};$.ajaxSetup=function() {return($);};$.ajaxTransport=function() {return($);};$.boxModel=function() {return($);};$.browser=function() {return($);};$.Callbacks=function() {return($);};$.contains=function() {return($);};$.cssHooks=function() {return($);};$.cssNumber=function() {return($);};$.data=function() {return($);};$.Deferred=function() {return($);};$.dequeue=function() {return($);};$.each=function() {return($);};$.error=function() {return($);};$.extend=function() {return($);};$.fnextend=function() {return($);};$.fxinterval=function() {return($);};$.fxoff=function() {return($);};$.get=function() {return($);};$.getJSON=function() {return($);};$.getScript=function() {return($);};$.globalEval=function() {return($);};$.grep=function() {return($);};$.hasData=function() {return($);};$.holdReady=function() {return($);};$.inArray=function() {return($);};$.isArray=function() {return($);};$.isEmptyObject=function() {return($);};$.isFunction=function() {return($);};$.isNumeric=function() {return($);};$.isPlainObject=function() {return($);};$.isWindow=function() {return($);};$.isXMLDoc=function() {return($);};$.makeArray=function() {return($);};$.map=function() {return($);};$.merge=function() {return($);};$.noConflict=function() {return($);};$.noop=function() {return($);};$.now=function() {return($);};$.param=function() {return($);};$.parseHTML=function() {return($);};$.parseJSON=function() {return($);};$.parseXML=function() {return($);};$.post=function() {return($);};$.proxy=function() {return($);};$.queue=function() {return($);};$.removeData=function() {return($);};$.sub=function() {return($);};$.support=function() {return($);};$.trim=function() {return($);};$.type=function() {return($);};$.unique=function() {return($);};$.when=function() {return($);};$.always=function() {return($);};$.done=function() {return($);};$.fail=function() {return($);};$.isRejected=function() {return($);};$.isResolved=function() {return($);};$.notify=function() {return($);};$.notifyWith=function() {return($);};$.pipe=function() {return($);};$.progress=function() {return($);};$.promise=function() {return($);};$.reject=function() {return($);};$.rejectWith=function() {return($);};$.resolve=function() {return($);};$.resolveWith=function() {return($);};$.state=function() {return($);};$.then=function() {return($);};$.currentTarget=function() {return($);};$.data=function() {return($);};$.delegateTarget=function() {return($);};$.isDefaultPrevented=function() {return($);};$.isImmediatePropagationStopped=function() {return($);};$.isPropagationStopped=function() {return($);};$.metaKey=function() {return($);};$.namespace=function() {return($);};$.pageX=function() {return($);};$.pageY=function() {return($);};$.preventDefault=function() {return($);};$.relatedTarget=function() {return($);};$.result=function() {return($);};$.stopImmediatePropagation=function() {return($);};$.stopPropagation=function() {return($);};$.target=function() {return($);};$.timeStamp=function() {return($);};$.type=function() {return($);};$.which=function() {return($);};' + s; + s = 'var document = ""; ' + + 'var $ = function() {' + + 'return new function() { this.add=function() { return this; };' + + 'this.addBack=function() {return this; };' + + 'this.addClass=function() {return this; };' + + 'this.after=function() {return this; };' + + 'this.ajaxComplete=function() {return this; };' + + 'this.ajaxError=function() {return this; };' + + 'this.ajaxSend=function() {return this; };' + + 'this.ajaxStart=function() {return this; };' + + 'this.ajaxStop=function() {return this; };' + + 'this.ajaxSuccess=function() {return this; };' + + 'this.andSelf=function() {return this; };' + + 'this.animate=function() {return this; };' + + 'this.append=function() {return this; };' + + 'this.appendTo=function() {return this; };' + + 'this.attr=function() {return this; };' + + 'this.before=function() {return this; };' + + 'this.bind=function() {return this; };' + + 'this.blur=function() {return this; };' + + 'this.callbacksadd=function() {return this; };' + + 'this.callbacksdisable=function() {return this; };' + + 'this.callbacksdisabled=function() {return this; };' + + 'this.callbacksempty=function() {return this; };' + + 'this.callbacksfire=function() {return this; };' + + 'this.callbacksfired=function() {return this; };' + + 'this.callbacksfireWith=function() {return this; };' + + 'this.callbackshas=function() {return this; };' + + 'this.callbackslock=function() {return this; };' + + 'this.callbackslocked=function() {return this; };' + + 'this.callbacksremove=function() {return this; };' + + 'this.change=function() {return this; };' + + 'this.children=function() {return this; };' + + 'this.clearQueue=function() {return this; };' + + 'this.click=function() {return this; };' + + 'this.clone=function() {return this; };' + + 'this.closest=function() {return this; };' + + 'this.contents=function() {return this; };' + + 'this.context=function() {return this; };' + + 'this.css=function() {return this; };' + + 'this.data=function() {return this; };' + + 'this.dblclick=function() {return this; };' + + 'this.delay=function() {return this; };' + + 'this.delegate=function() {return this; };' + + 'this.dequeue=function() {return this; };' + + 'this.detach=function() {return this; };' + + 'this.die=function() {return this; };' + + 'this.each=function() {return this; };' + + 'this.empty=function() {return this; };' + + 'this.end=function() {return this; };' + + 'this.eq=function() {return this; };' + + 'this.error=function() {return this; };' + + 'this.fadeIn=function() {return this; };' + + 'this.fadeOut=function() {return this; };' + + 'this.fadeTo=function() {return this; };' + + 'this.fadeToggle=function() {return this; };' + + 'this.filter=function() {return this; };' + + 'this.find=function() {return this; };' + + 'this.finish=function() {return this; };' + + 'this.first=function() {return this; };' + + 'this.focus=function() {return this; };' + + 'this.focusin=function() {return this; };' + + 'this.focusout=function() {return this; };' + + 'this.get=function() {return this; };' + + 'this.has=function() {return this; };' + + 'this.hasClass=function() {return this; };' + + 'this.height=function() {return this; };' + + 'this.hide=function() {return this; };' + + 'this.hover=function() {return this; };' + + 'this.html=function() {return this; };' + + 'this.index=function() {return this; };' + + 'this.innerHeight=function() {return this; };' + + 'this.innerWidth=function() {return this; };' + + 'this.insertAfter=function() {return this; };' + + 'this.insertBefore=function() {return this; };' + + 'this.is=function() {return this; };' + + 'this.jQuery=function() {return this; };' + + 'this.jquery=function() {return this; };' + + 'this.keydown=function() {return this; };' + + 'this.keypress=function() {return this; };' + + 'this.keyup=function() {return this; };' + + 'this.last=function() {return this; };' + + 'this.length=function() {return this; };' + + 'this.live=function() {return this; };' + + 'this.load=function() {return this; };' + + 'this.load=function() {return this; };' + + 'this.map=function() {return this; };' + + 'this.mousedown=function() {return this; };' + + 'this.mouseenter=function() {return this; };' + + 'this.mouseleave=function() {return this; };' + + 'this.mousemove=function() {return this; };' + + 'this.mouseout=function() {return this; };' + + 'this.mouseover=function() {return this; };' + + 'this.mouseup=function() {return this; };' + + 'this.next=function() {return this; };' + + 'this.nextAll=function() {return this; };' + + 'this.nextUntil=function() {return this; };' + + 'this.not=function() {return this; };' + + 'this.off=function() {return this; };' + + 'this.offset=function() {return this; };' + + 'this.offsetParent=function() {return this; };' + + 'this.on=function() {return this; };' + + 'this.one=function() {return this; };' + + 'this.outerHeight=function() {return this; };' + + 'this.outerWidth=function() {return this; };' + + 'this.parent=function() {return this; };' + + 'this.parents=function() {return this; };' + + 'this.parentsUntil=function() {return this; };' + + 'this.position=function() {return this; };' + + 'this.prepend=function() {return this; };' + + 'this.prependTo=function() {return this; };' + + 'this.prev=function() {return this; };' + + 'this.prevAll=function() {return this; };' + + 'this.prevUntil=function() {return this; };' + + 'this.promise=function() {return this; };' + + 'this.prop=function() {return this; };' + + 'this.pushStack=function() {return this; };' + + 'this.queue=function() {return this; };' + + 'this.ready=function() {return this; };' + + 'this.remove=function() {return this; };' + + 'this.removeAttr=function() {return this; };' + + 'this.removeClass=function() {return this; };' + + 'this.removeData=function() {return this; };' + + 'this.removeProp=function() {return this; };' + + 'this.replaceAll=function() {return this; };' + + 'this.replaceWith=function() {return this; };' + + 'this.resize=function() {return this; };' + + 'this.scroll=function() {return this; };' + + 'this.scrollLeft=function() {return this; };' + + 'this.scrollTop=function() {return this; };' + + 'this.select=function() {return this; };' + + 'this.selector=function() {return this; };' + + 'this.serialize=function() {return this; };' + + 'this.serializeArray=function() {return this; };' + + 'this.show=function() {return this; };' + + 'this.siblings=function() {return this; };' + + 'this.size=function() {return this; };' + + 'this.slice=function() {return this; };' + + 'this.slideDown=function() {return this; };' + + 'this.slideToggle=function() {return this; };' + + 'this.slideUp=function() {return this; };' + + 'this.stop=function() {return this; };' + + 'this.submit=function() {return this; };' + + 'this.text=function() {return this; };' + + 'this.toArray=function() {return this; };' + + 'this.toggle=function() {return this; };' + + 'this.toggle=function() {return this; };' + + 'this.toggleClass=function() {return this; };' + + 'this.trigger=function() {return this; };' + + 'this.triggerHandler=function() {return this; };' + + 'this.unbind=function() {return this; };' + + 'this.undelegate=function() {return this; };' + + 'this.unload=function() {return this; };' + + 'this.unwrap=function() {return this; };' + + 'this.val=function() {return this; };' + + 'this.width=function() {return this; };' + + 'this.wrap=function() {return this; };' + + 'this.wrapAll=function() {return this; };' + + 'this.wrapInner=function() {return this; };};};' + + '$.ajax=function() {return $;};' + + '$.ajaxPrefilter=function() {return $; };' + + '$.ajaxSetup=function() {return $; };' + + '$.ajaxTransport=function() {return $; };' + + '$.boxModel=function() {return $; };' + + '$.browser=function() {return $; };' + + '$.Callbacks=function() {return $; };' + + '$.contains=function() {return $; };' + + '$.cssHooks=function() {return $; };' + + '$.cssNumber=function() {return $; };' + + '$.data=function() {return $; };' + + '$.Deferred=function() {return $; };' + + '$.dequeue=function() {return $; };' + + '$.each=function() {return $; };' + + '$.error=function() {return $; };' + + '$.extend=function() {return $; };' + + '$.fnextend=function() {return $; };' + + '$.fxinterval=function() {return $; };' + + '$.fxoff=function() {return $; };' + + '$.get=function() {return $; };' + + '$.getJSON=function() {return $; };' + + '$.getScript=function() {return $; };' + + '$.globalEval=function() {return $; };' + + '$.grep=function() {return $; };' + + '$.hasData=function() {return $; };' + + '$.holdReady=function() {return $; };' + + '$.inArray=function() {return $; };' + + '$.isArray=function() {return $; };' + + '$.isEmptyObject=function() {return $; };' + + '$.isFunction=function() {return $; };' + + '$.isNumeric=function() {return $; };' + + '$.isPlainObject=function() {return $; };' + + '$.isWindow=function() {return $; };' + + '$.isXMLDoc=function() {return $; };' + + '$.makeArray=function() {return $; };' + + '$.map=function() {return $; };' + + '$.merge=function() {return $; };' + + '$.noConflict=function() {return $; };' + + '$.noop=function() {return $; };' + + '$.now=function() {return $; };' + + '$.param=function() {return $; };' + + '$.parseHTML=function() {return $; };' + + '$.parseJSON=function() {return $; };' + + '$.parseXML=function() {return $; };' + + '$.post=function() {return $; };' + + '$.proxy=function() {return $; };' + + '$.queue=function() {return $; };' + + '$.removeData=function() {return $; };' + + '$.sub=function() {return $; };' + + '$.support=function() {return $; };' + + '$.trim=function() {return $; };' + + '$.type=function() {return $; };' + + '$.unique=function() {return $; };' + + '$.when=function() {return $; };' + + '$.always=function() {return $; };' + + '$.done=function() {return $; };' + + '$.fail=function() {return $; };' + + '$.isRejected=function() {return $; };' + + '$.isResolved=function() {return $; };' + + '$.notify=function() {return $; };' + + '$.notifyWith=function() {return $; };' + + '$.pipe=function() {return $; };' + + '$.progress=function() {return $; };' + + '$.promise=function() {return $; };' + + '$.reject=function() {return $; };' + + '$.rejectWith=function() {return $; };' + + '$.resolve=function() {return $; };' + + '$.resolveWith=function() {return $; };' + + '$.state=function() {return $; };' + + '$.then=function() {return $; };' + + '$.currentTarget=function() {return $; };' + + '$.data=function() {return $; };' + + '$.delegateTarget=function() {return $; };' + + '$.isDefaultPrevented=function() {return $; };' + + '$.isImmediatePropagationStopped=function() {return $; };' + + '$.isPropagationStopped=function() {return $; };' + + '$.metaKey=function() {return $; };' + + '$.namespace=function() {return $; };' + + '$.pageX=function() {return $; };' + + '$.pageY=function() {return $; };' + + '$.preventDefault=function() {return $; };' + + '$.relatedTarget=function() {return $; };' + + '$.result=function() {return $; };' + + '$.stopImmediatePropagation=function() {return $; };' + + '$.stopPropagation=function() {return $; };' + + '$.target=function() {return $; };' + + '$.timeStamp=function() {return $; };' + + '$.type=function() {return $; };' + + '$.which=function() {return $; };' + + '' + s; // add spoofigator - s = " var navigator = " + - "function(){" + - " this.geolocation=function(){" + - " this.getCurrentPosition=function(){" + - " this.coords = {latitude: \"\", longitude: \"\"};" + - " return(this);" + - " };" + - " return(this);" + - " };" + - " return(this);" + - "};" + s; + s = ' var navigator = ' + + 'function() {' + + ' this.geolocation=function() {' + + ' this.getCurrentPosition=function() {' + + ' this.coords = {latitude: "", longitude: ""};' + + ' return this;' + + ' };' + + ' return this;' + + ' };' + + ' return this;' + + '};' + s; sandBox.submit(scopejQuery(s), function(cls, message) { if (cls) { @@ -582,14 +841,14 @@ function safeHTMLRun(test) { function updatePreview() { editorValueForIFrame = editor.getValue(); var failedCommentTest = false; + var openingComments = editorValueForIFrame.match(/\<\!\-\-/gi); + var closingComments = editorValueForIFrame.match(/\-\-\>/gi); if ( - editorValueForIFrame.match(/\<\!\-\-/gi) && - editorValueForIFrame.match(/\-\-\>/gi) == null - ) { - failedCommentTest = true; - } else if ( - editorValueForIFrame.match(/\<\!\-\-/gi) && - editorValueForIFrame.match(/\<\!\-\-/gi).length > editorValueForIFrame.match(/\-\-\>/gi).length + openingComments && + ( + !closingComments || + openingComments.length > closingComments.length + ) ) { failedCommentTest = true; } @@ -630,7 +889,9 @@ var postSuccess = function(data) { var testDoc = document.createElement('div'); $(testDoc).html( - "
" + + "
" + + "
" + + "
" + JSON.parse(data) + '
' ); @@ -639,11 +900,15 @@ var postSuccess = function(data) { testSuccess(); }; +/* eslint-disable no-unused-vars */ var postError = function(data) { +/* eslint-enable no-unused-vars */ var testDoc = document.createElement('div'); $(testDoc).html( - "
" + + "
" + + "
" + + "
" + JSON.parse(data) + '
' ); @@ -1113,11 +1378,12 @@ function bonfireExecute(shouldTest) { var userJavaScript = editor.getValue(); var failedCommentTest = false; + var openingComments = userJavaScript.match(/\/\*/gi); // checks if the number of opening comments(/*) matches the number of // closing comments(*/) if ( - userJavaScript.match(/\/\*/gi) && - userJavaScript.match(/\/\*/gi).length > userJavaScript.match(/\*\//gi).length + openingComments && + openingComments.length > userJavaScript.match(/\*\//gi).length ) { failedCommentTest = true; } diff --git a/client/iFrameScripts.js b/client/iFrameScripts.js index 1d5db5413d..61c4c66fe5 100644 --- a/client/iFrameScripts.js +++ b/client/iFrameScripts.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef, no-unused-vars, no-native-reassign */ (function() { var expect = chai.expect; var tests = parent.tests; @@ -7,7 +8,9 @@ for (var i = 0; i < tests.length; i++) { var thisTest = true; try { + /* eslint-disable no-eval */ eval(parent.tests[i]); + /* eslint-enable no-eval */ } catch (err) { allTestsGood = false; thisTest = false; diff --git a/client/plugin.js b/client/plugin.js index 36f869db1a..f53d68c71a 100644 --- a/client/plugin.js +++ b/client/plugin.js @@ -23,7 +23,7 @@ function run(code) { var codeExec = runHidden(code); result.type = typeof codeExec; result.output = stringify(codeExec); - } catch(e) { + } catch (e) { result.error = e.message; } From c94a61ab0c901eb454503ceb2dfecd7c4367fb9b Mon Sep 17 00:00:00 2001 From: Rex Schrader Date: Wed, 4 Nov 2015 13:23:25 -0800 Subject: [PATCH 11/79] Fixes 4165 - Spurious backslash in Update Object Properties test --- seed/challenges/basic-javascript.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed/challenges/basic-javascript.json b/seed/challenges/basic-javascript.json index c8663c4f27..004ae5ba42 100644 --- a/seed/challenges/basic-javascript.json +++ b/seed/challenges/basic-javascript.json @@ -752,7 +752,7 @@ "Let's update the myDog object's name property. Let's change her name from \"Coder\" to \"Happy Coder\"." ], "tests": [ - "assert(/happy coder/gi.test(myDog.name), 'message: Update myDog\\'s \"name\" property to equal \"Happy Coder\".');" + "assert(/happy coder/gi.test(myDog.name), 'message: Update myDog's \"name\" property to equal \"Happy Coder\".');" ], "challengeSeed": [ "var ourDog = {", From 8d28da348583622f28d81d99ee8da26fbc3abd61 Mon Sep 17 00:00:00 2001 From: SaintPeter Date: Wed, 4 Nov 2015 21:46:56 -0800 Subject: [PATCH 12/79] Fix a missing code tag in condense arrays waypoint --- seed/challenges/object-oriented-and-functional-programming.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed/challenges/object-oriented-and-functional-programming.json b/seed/challenges/object-oriented-and-functional-programming.json index 810fc81323..6a6a1599e3 100644 --- a/seed/challenges/object-oriented-and-functional-programming.json +++ b/seed/challenges/object-oriented-and-functional-programming.json @@ -225,7 +225,7 @@ "description":[ "The array method reduce is used to iterate through an array and condense it into one value.", "To use reduce you pass in a callback whose arguments are an accumulator (in this case, previousVal) and the current value (currentVal).", - "reduce has an optional second argument which can be used to set the initial value of the accumulator. If no initial value is specified it will be the first array element and currentVal will start with the second array element.", + "reduce has an optional second argument which can be used to set the initial value of the accumulator. If no initial value is specified it will be the first array element and currentVal will start with the second array element.", "Here is an example of reduce being used to subtract all the values of an array:", "var singleVal = array.reduce(function(previousVal, currentVal) {", "  return previousVal - currentVal;", From 42b55233284426ac258a4512b1c3132f0bd2d7af Mon Sep 17 00:00:00 2001 From: venky18 Date: Thu, 5 Nov 2015 23:16:23 +0530 Subject: [PATCH 13/79] added a semicolon on line 1483 there is a semicolon missing on line 16 of the editor in the url http://www.freecodecamp.com/challenges/waypoint-create-a-javascript-slot-machine --- seed/challenges/basic-javascript.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed/challenges/basic-javascript.json b/seed/challenges/basic-javascript.json index 004ae5ba42..fd7ac4efcb 100644 --- a/seed/challenges/basic-javascript.json +++ b/seed/challenges/basic-javascript.json @@ -1480,7 +1480,7 @@ " slotThree = Math.floor(Math.random() * (3 - 1 + 1)) + 1;", " ", " $(\".logger\").html(\"\");", - " $(\".logger\").html(\"Not A Win\")", + " $(\".logger\").html(\"Not A Win\");", " ", " // Only change code below this line.", " ", From 173c5110264d41b8c4f6e39a4211752fd18fe19e Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Wed, 4 Nov 2015 13:04:17 -0800 Subject: [PATCH 14/79] Remove old cert stuff --- common/app/routes/Jobs/components/NewJob.jsx | 47 -------------------- 1 file changed, 47 deletions(-) diff --git a/common/app/routes/Jobs/components/NewJob.jsx b/common/app/routes/Jobs/components/NewJob.jsx index e4f01d73c4..a3535290d8 100644 --- a/common/app/routes/Jobs/components/NewJob.jsx +++ b/common/app/routes/Jobs/components/NewJob.jsx @@ -45,18 +45,6 @@ const hightlightCopy = ` Highlight my post to make it stand out. (+$50) `; -const foo = ` - This will narrow the field substantially with higher quality applicants -`; - -const isFullStackCopy = ` -Applicants must have earned Free Code Camp’s Full Stack Certification to apply.* -`; - -const isFrontEndCopy = ` -Applicants must have earned Free Code Camp’s Front End Certification to apply.* -`; - const isRemoteCopy = ` This job can be performed remotely. `; @@ -126,8 +114,6 @@ export default contain({ logo, company, isHighlighted, - isFullStackCert, - isFrontEndCert, isRemoteOk, howToApply } = form; @@ -140,8 +126,6 @@ export default contain({ logo: formatValue(formatUrl(logo), isValidURL), company: formatValue(company, makeRequired(isAscii)), isHighlighted: formatValue(isHighlighted, null, 'bool'), - isFullStackCert: formatValue(isFullStackCert, null, 'bool'), - isFrontEndCert: formatValue(isFrontEndCert, null, 'bool'), isRemoteOk: formatValue(isRemoteOk, null, 'bool'), howToApply: formatValue(howToApply, makeRequired(isAscii)) }; @@ -163,8 +147,6 @@ export default contain({ logo: PropTypes.object, company: PropTypes.object, isHighlighted: PropTypes.object, - isFullStackCert: PropTypes.object, - isFrontEndCert: PropTypes.object, isRemoteOk: PropTypes.object, howToApply: PropTypes.object }, @@ -199,8 +181,6 @@ export default contain({ logo, company, isHighlighted, - isFullStackCert, - isFrontEndCert, isRemoteOk, howToApply } = this.props; @@ -215,8 +195,6 @@ export default contain({ logo: formatUrl(uriInSingleQuotedAttr(logo.value), false), company: inHTMLData(company.value), isHighlighted: !!isHighlighted.value, - isFrontEndCert: !!isFrontEndCert.value, - isFullStackCert: !!isFullStackCert.value, isRemoteOk: !!isRemoteOk.value, howToApply: inHTMLData(howToApply.value) }; @@ -255,8 +233,6 @@ export default contain({ logo, company, isHighlighted, - isFrontEndCert, - isFullStackCert, isRemoteOk, howToApply, jobActions: { handleForm } @@ -311,26 +287,6 @@ export default contain({ type='textarea' value={ description.value } wrapperClassName={ inputClass } /> - handleForm({ - isFrontEndCert: !!checked - }) - } - type='checkbox' - wrapperClassName={ checkboxClass } /> - handleForm({ - isFullStackCert: !!checked - }) - } - type='checkbox' - wrapperClassName={ checkboxClass } /> - - * { foo } -
From 1251b14d9de849ec7ef1f7353171af6340a642a8 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Wed, 4 Nov 2015 13:45:22 -0800 Subject: [PATCH 15/79] Add job cert buttons --- common/app/routes/Jobs/components/NewJob.jsx | 53 ++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/common/app/routes/Jobs/components/NewJob.jsx b/common/app/routes/Jobs/components/NewJob.jsx index a3535290d8..6dce6817c0 100644 --- a/common/app/routes/Jobs/components/NewJob.jsx +++ b/common/app/routes/Jobs/components/NewJob.jsx @@ -45,6 +45,7 @@ const hightlightCopy = ` Highlight my post to make it stand out. (+$50) `; + const isRemoteCopy = ` This job can be performed remotely. `; @@ -113,6 +114,8 @@ export default contain({ url, logo, company, + isFrontEndCert, + isFullStackCert, isHighlighted, isRemoteOk, howToApply @@ -127,7 +130,9 @@ export default contain({ company: formatValue(company, makeRequired(isAscii)), isHighlighted: formatValue(isHighlighted, null, 'bool'), isRemoteOk: formatValue(isRemoteOk, null, 'bool'), - howToApply: formatValue(howToApply, makeRequired(isAscii)) + howToApply: formatValue(howToApply, makeRequired(isAscii)), + isFrontEndCert, + isFullStackCert }; }, subscribeOnWillMount() { @@ -148,6 +153,8 @@ export default contain({ company: PropTypes.object, isHighlighted: PropTypes.object, isRemoteOk: PropTypes.object, + isFrontEndCert: PropTypes.bool, + isFullStackCert: PropTypes.bool, howToApply: PropTypes.object }, @@ -180,6 +187,8 @@ export default contain({ url, logo, company, + isFrontEndCert, + isFullStackCert, isHighlighted, isRemoteOk, howToApply @@ -196,7 +205,9 @@ export default contain({ company: inHTMLData(company.value), isHighlighted: !!isHighlighted.value, isRemoteOk: !!isRemoteOk.value, - howToApply: inHTMLData(howToApply.value) + howToApply: inHTMLData(howToApply.value), + isFrontEndCert, + isFullStackCert }; const job = Object.keys(jobValues).reduce((accu, prop) => { @@ -235,8 +246,11 @@ export default contain({ isHighlighted, isRemoteOk, howToApply, + isFrontEndCert, + isFullStackCert, jobActions: { handleForm } } = this.props; + const { handleChange } = this; const labelClass = 'col-sm-offset-1 col-sm-2'; const inputClass = 'col-sm-6'; @@ -253,7 +267,40 @@ export default contain({ onSubmit={ this.handleSubmit }>
-

First, tell us about the position

+

First, select your ideal applicant:

+
+ + + + + + +
+ + + + + +
+

Tell us about the position

Date: Wed, 4 Nov 2015 14:23:42 -0800 Subject: [PATCH 16/79] Add logic to cert buttons --- common/app/routes/Jobs/components/NewJob.jsx | 28 +++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/common/app/routes/Jobs/components/NewJob.jsx b/common/app/routes/Jobs/components/NewJob.jsx index 6dce6817c0..9697e420c4 100644 --- a/common/app/routes/Jobs/components/NewJob.jsx +++ b/common/app/routes/Jobs/components/NewJob.jsx @@ -114,7 +114,7 @@ export default contain({ url, logo, company, - isFrontEndCert, + isFrontEndCert = true, isFullStackCert, isHighlighted, isRemoteOk, @@ -171,7 +171,7 @@ export default contain({ } }); - if (!valid) { + if (!valid || !props.isFrontEndCert && !props.isFullStackCert ) { debug('form not valid'); return; } @@ -234,6 +234,18 @@ export default contain({ handleForm({ [name]: value }); }, + handleCertClick(name) { + const { jobActions: { handleForm } } = this.props; + const otherButton = name === 'isFrontEndCert' ? + 'isFullStackCert' : + 'isFrontEndCert'; + + handleForm({ + [name]: true, + [otherButton]: false + }); + }, + render() { const { position, @@ -275,7 +287,11 @@ export default contain({ xs={ 6 } xsOffset={ 3 }> - @@ -305,9 +307,11 @@ export default contain({ - ); - } - return null; - }, - - render: function() { - var isDescription = this.props.description && - this.props.description.length > 1; - - return ( -
-

{ this.props.name }

-

-
- Difficulty:  - { this._renderFlames() } -
-

- - - -
-

{ this.props.brief }

-
- { this._renderMoreInfo(isDescription) } - { this._renderMoreInfoButton(isDescription) } -
-
- -
-
- -
-
- ); - } -}); - -module.exports = SidePanel; diff --git a/common/app/routes/Bonfires/executeBonfire.js b/common/app/routes/Bonfires/executeBonfire.js deleted file mode 100644 index 0d1795894a..0000000000 --- a/common/app/routes/Bonfires/executeBonfire.js +++ /dev/null @@ -1,27 +0,0 @@ -var debug = require('debug')('freecc:executebonfire'); -var { - addTests, - runTests, - testCode -} = require('../../utils'); - -module.exports = executeBonfire; - -function executeBonfire(userCode, tests, cb) { - - // TODO: move this into componentDidMount - // ga('send', 'event', 'Bonfire', 'ran-code', bonfireName); - var testSalt = Math.random(); - var { preppedCode, userTests } = addTests(userCode, tests, testSalt); - - debug('sending code to web worker for testing'); - testCode(preppedCode, function(err, data) { - if (err) { return cb(err); } - var results = runTests(userTests, data, testSalt); - debug('testing complete', results); - cb(null, { - output: data.output, - results - }); - }); -} diff --git a/common/app/routes/Bonfires/index.js b/common/app/routes/Bonfires/index.js deleted file mode 100644 index ec633552eb..0000000000 --- a/common/app/routes/Bonfires/index.js +++ /dev/null @@ -1,8 +0,0 @@ -/* -export default { - path: 'bonfires/(:bonfireName)' - getComponents(cb) { - // TODO(berks): add bonfire component - } -}; -*/ diff --git a/common/app/routes/Jobs/components/JobNotFound.jsx b/common/app/routes/Jobs/components/JobNotFound.jsx index b921dfd4dc..c4981d22f8 100644 --- a/common/app/routes/Jobs/components/JobNotFound.jsx +++ b/common/app/routes/Jobs/components/JobNotFound.jsx @@ -1,8 +1,8 @@ -import React, { createClass } from 'react'; +import React from 'react'; import { LinkContainer } from 'react-router-bootstrap'; import { Button, Row, Col, Panel } from 'react-bootstrap'; -export default createClass({ +export default React.createClass({ displayName: 'NoJobFound', render() { diff --git a/common/app/routes/Jobs/components/NewJob.jsx b/common/app/routes/Jobs/components/NewJob.jsx index 661ea70367..2d0bd08937 100644 --- a/common/app/routes/Jobs/components/NewJob.jsx +++ b/common/app/routes/Jobs/components/NewJob.jsx @@ -162,16 +162,16 @@ export default contain({ handleSubmit(e) { e.preventDefault(); - const props = this.props; + const pros = this.props; let valid = true; checkValidity.forEach((prop) => { // if value exist, check if it is valid - if (props[prop].value && props[prop].type !== 'boolean') { - valid = valid && !!props[prop].valid; + if (pros[prop].value && pros[prop].type !== 'boolean') { + valid = valid && !!pros[prop].valid; } }); - if (!valid || !props.isFrontEndCert && !props.isFullStackCert ) { + if (!valid || !pros.isFrontEndCert && !pros.isFullStackCert ) { debug('form not valid'); return; } diff --git a/common/app/routes/Jobs/components/TwitterBtn.jsx b/common/app/routes/Jobs/components/TwitterBtn.jsx index fb5f8edf12..7998353ffc 100644 --- a/common/app/routes/Jobs/components/TwitterBtn.jsx +++ b/common/app/routes/Jobs/components/TwitterBtn.jsx @@ -1,4 +1,4 @@ -import React, { createClass, PropTypes } from 'react'; +import React, { PropTypes } from 'react'; import { Button } from 'react-bootstrap'; const followLink = 'https://twitter.com/intent/follow?' + @@ -9,7 +9,7 @@ function commify(count) { return Number(count).toLocaleString('en'); } -export default createClass({ +export default React.createClass({ displayName: 'FollowButton', diff --git a/common/app/shared/displayCode/Display.jsx b/common/app/shared/displayCode/Display.jsx deleted file mode 100644 index 9eb60db8da..0000000000 --- a/common/app/shared/displayCode/Display.jsx +++ /dev/null @@ -1,51 +0,0 @@ -var React = require('react'), - Tailspin = require('tailspin'); - -var Editor = React.createClass({ - - propTypes: { - value: React.PropTypes.string - }, - - getDefaultProps: function() { - return { - value: [ - '/**', - '* Your output will go here.', - '* Console.log() -type statements', - '* will appear in your browser\'s', - '* DevTools JavaScript console.', - '**/' - ].join('\n') - }; - }, - - render: function() { - var value = this.props.value; - var options = { - lineNumbers: false, - lineWrapping: true, - mode: 'text', - readOnly: 'noCursor', - textAreaClassName: 'hide-textarea', - theme: 'monokai', - value: value - }; - - var config = { - setSize: ['100%', '100%'] - }; - - return ( -
-
- -
-
- ); - } -}); - -module.exports = Editor; diff --git a/common/app/shared/displayCode/index.js b/common/app/shared/displayCode/index.js deleted file mode 100644 index d3e3560174..0000000000 --- a/common/app/shared/displayCode/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./Display.jsx'); diff --git a/common/app/shared/editor/Editor.jsx b/common/app/shared/editor/Editor.jsx deleted file mode 100644 index 8e72f5d4a0..0000000000 --- a/common/app/shared/editor/Editor.jsx +++ /dev/null @@ -1,91 +0,0 @@ -var React = require('react'), - debug = require('debug')('freecc:comp:editor'), - jshint = require('jshint').JSHINT, - Tailspin = require('tailspin'); - -var Editor = React.createClass({ - - propTypes: { - onValueChange: React.PropTypes.func, - value: React.PropTypes.string - }, - - getDefaultProps: function() { - return { - value: 'console.log(\'freeCodeCamp is awesome\')' - }; - }, - - getInitialState: function() { - return { - value: this.props.value - }; - }, - - render: function() { - var options = { - autoCloseBrackets: true, - gutters: ['CodeMirror-lint-markers'], - lint: true, - linter: jshint, - lineNumbers: true, - lineWrapping: true, - mode: 'javascript', - matchBrackets: true, - runnable: true, - scrollbarStyle: 'null', - theme: 'monokai', - textAreaClassName: 'hide-textarea', - value: this.state.value, - onChange: e => { - this.setState({ value: e.target.value}); - if (typeof this.props.onValueChange === 'function') { - this.props.onValueChange(e.target.value); - } - } - }; - - var config = { - setSize: ['100%', 'auto'], - extraKeys: { - Tab: function(cm) { - debug('tab pressed'); - if (cm.somethingSelected()) { - cm.indentSelection('add'); - } else { - var spaces = new Array(cm.getOption('indentUnit') + 1).join(' '); - cm.replaceSelection(spaces); - } - }, - 'Shift-Tab': function(cm) { - debug('shift-tab pressed'); - if (cm.somethingSelected()) { - cm.indentSelection('subtract'); - } else { - var spaces = new Array(cm.getOption('indentUnit') + 1).join(' '); - cm.replaceSelection(spaces); - } - }, - 'Ctrl-Enter': function() { - debug('C-enter pressed'); - // execute bonfire action - return false; - } - } - }; - - return ( -
-
-
- -
-
-
- ); - } -}); - -module.exports = Editor; diff --git a/common/app/shared/editor/index.js b/common/app/shared/editor/index.js deleted file mode 100644 index 5e431fabff..0000000000 --- a/common/app/shared/editor/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./Editor.jsx'); diff --git a/package.json b/package.json index ef06329143..4e36abf74f 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "lint-server": "jsonlint -q server/*.json", "lint-resources": "jsonlint -q server/resources/*.json", "lint-utils": "jsonlint -q server/utils/*.json", - "lint-js": "eslint --ext=.js,.jsx server/ common/models common/utils config/", + "lint-js": "eslint --ext=.js,.jsx server/ common/ common/utils config/ client/", "lint-json": "npm run lint-server && npm run lint-nonprofits && npm run lint-challenges && npm run lint-resources && npm run lint-utils", "test-challenges": "babel-node seed/test-challenges.js | tnyan", "pretest": "npm run lint", From 085fc2fe72cc8085292cb47a4c2b8bedce009d42 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Thu, 5 Nov 2015 16:41:19 -0800 Subject: [PATCH 24/79] Fix loopback explorer issue --- package.json | 3 ++- server/boot/explorer.js | 15 +++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 75db855279..537afc32fd 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "lodash": "^3.9.3", "loopback": "^2.22.0", "loopback-boot": "^2.13.0", + "loopback-component-explorer": "^2.1.1", "loopback-component-passport": "https://github.com/FreeCodeCamp/loopback-component-passport.git#feature/flashfailure", "loopback-connector-mongodb": "^1.10.0", "lusca": "~1.3.0", @@ -137,7 +138,7 @@ "envify": "^3.4.0", "istanbul": "^0.4.0", "jsonlint": "^1.6.2", - "loopback-explorer": "^2.0.2", + "loopback-component-explorer": "^2.1.1", "loopback-testing": "^1.1.0", "mocha": "~2.3.3", "multiline": "~1.0.1", diff --git a/server/boot/explorer.js b/server/boot/explorer.js index 955b23573d..4480abecc7 100644 --- a/server/boot/explorer.js +++ b/server/boot/explorer.js @@ -4,27 +4,26 @@ module.exports = function mountLoopBackExplorer(app) { } var explorer; try { - explorer = require('loopback-explorer'); + explorer = require('loopback-component-explorer'); } catch (err) { // Print the message only when the app was started via `app.listen()`. // Do not print any message when the project is used as a component. app.once('started', function() { console.log( - 'Run `npm install loopback-explorer` to enable the LoopBack explorer' + 'Run `npm install loopback-component-explorer` to enable ' + + 'the LoopBack explorer' ); }); return; } var restApiRoot = app.get('restApiRoot'); + var mountPath = '/explorer'; - var explorerApp = explorer(app, { basePath: restApiRoot }); - app.use('/explorer', explorerApp); + explorer(app, { basePath: restApiRoot, mountPath }); app.once('started', function() { var baseUrl = app.get('url').replace(/\/$/, ''); - // express 4.x (loopback 2.x) uses `mountpath` - // express 3.x (loopback 1.x) uses `route` - var explorerPath = explorerApp.mountpath || explorerApp.route; - console.log('Browse your REST API at %s%s', baseUrl, explorerPath); + + console.log('Browse your REST API at %s%s', baseUrl, mountPath); }); }; From 00fcdc9bc17bf5068313d7cc8d807e9fa9f4713a Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Thu, 5 Nov 2015 17:06:13 -0800 Subject: [PATCH 25/79] Fix news username query should be case insensitive --- server/boot/story.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/server/boot/story.js b/server/boot/story.js index 58a4c53fc4..ff20a9cd62 100755 --- a/server/boot/story.js +++ b/server/boot/story.js @@ -105,27 +105,6 @@ module.exports = function(app) { ); } - function userStories({ body: { search = '' } = {} }, res, next) { - if (!search || typeof search !== 'string') { - return res.sendStatus(404); - } - - return app.dataSources.db.connector - .collection('story') - .find({ - 'author.username': search.replace('$', '') - }) - .toArray(function(err, items) { - if (err) { - return next(err); - } - if (items && items.length !== 0) { - return res.json(items.sort(sortByRank)); - } - return res.sendStatus(404); - }); - } - function hot(req, res) { return res.render('stories/index', { title: 'Top Stories on Camper News', @@ -225,6 +204,27 @@ module.exports = function(app) { ); } + function userStories({ body: { search = '' } = {} }, res, next) { + if (!search || typeof search !== 'string') { + return res.sendStatus(404); + } + + return app.dataSources.db.connector + .collection('story') + .find({ + 'author.username': search.toLowerCase().replace('$', '') + }) + .toArray(function(err, items) { + if (err) { + return next(err); + } + if (items && items.length !== 0) { + return res.json(items.sort(sortByRank)); + } + return res.sendStatus(404); + }); + } + function getStories({ body: { search = '' } = {} }, res, next) { if (!search || typeof search !== 'string') { return res.sendStatus(404); From deb9bce3da849f7fe3706910ba7a71d58bcc4caa Mon Sep 17 00:00:00 2001 From: SaintPeter Date: Thu, 5 Nov 2015 22:02:55 -0800 Subject: [PATCH 26/79] Fixes typo in Join Strings with Join Waypoint --- seed/challenges/object-oriented-and-functional-programming.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed/challenges/object-oriented-and-functional-programming.json b/seed/challenges/object-oriented-and-functional-programming.json index 6a6a1599e3..85c5cdc94b 100644 --- a/seed/challenges/object-oriented-and-functional-programming.json +++ b/seed/challenges/object-oriented-and-functional-programming.json @@ -410,7 +410,7 @@ "title":"Join Strings with .join", "description":[ "We can use the join method to join each element of an array into a string separated by whatever delimiter you provide as an argument.", - "The following is an example of using join to join all of the elements of an array into a string with all the elements seperated by word `Na`:", + "The following is an example of using join to join all of the elements of an array into a string with all the elements separated by word `Na`:", "var joinMe = [\"Na \", \"Na \", \"Na \", \"Na \", \"Batman!\"];", "var joinedString = joinMe.join(\"Na \");", "console.log(joinedString);", From 172b28c664caeb24221071b806af56f69d1c0421 Mon Sep 17 00:00:00 2001 From: Rex Schrader Date: Fri, 6 Nov 2015 10:26:56 -0800 Subject: [PATCH 27/79] Truncate String - add test, solution --- seed/challenges/basic-bonfires.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/seed/challenges/basic-bonfires.json b/seed/challenges/basic-bonfires.json index 505b91fd5e..6171cb94e4 100644 --- a/seed/challenges/basic-bonfires.json +++ b/seed/challenges/basic-bonfires.json @@ -410,12 +410,14 @@ "assert(truncate(\"Peter Piper picked a peck of pickled peppers\", 14) === \"Peter Piper...\", 'message: truncate(\"Peter Piper picked a peck of pickled peppers\", 14) should return \"Peter Piper...\".');", "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\", 'message: truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length) should return \"A-tisket a-tasket A green and yellow basket\".');", "assert(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', 'message: truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length + 2) should return \"A-tisket a-tasket A green and yellow basket\".');", - "assert(truncate(\"A-\", 1) === \"A...\", 'message: truncate(\"A-\", 1) should return \"A...\".');" + "assert(truncate(\"A-\", 1) === \"A...\", 'message: truncate(\"A-\", 1) should return \"A...\".');", + "assert(truncate(\"Abolutely Longer\", 2) === \"Ab...\", 'message: truncate(\"Absolutely Longer\", 2) should return \"Ab...\".');" ], "MDNlinks": [ "String.slice()" ], "solutions": [ + "function truncate(str, num) {\n if(str.length > num ) {\n if(num > 3) {\n return str.slice(0, num - 3) + '...';\n } else {\n return str.slice(0,num) + '...';\n }\n } \n return str;\n}" ], "type": "bonfire", "challengeType": 5, From ef560ddb3ebb8b8f76df78d77030b7ced87b45e4 Mon Sep 17 00:00:00 2001 From: Faizaan Date: Sat, 7 Nov 2015 05:50:04 +0530 Subject: [PATCH 28/79] fixes #4062 --- seed/challenges/basic-bonfires.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/seed/challenges/basic-bonfires.json b/seed/challenges/basic-bonfires.json index 6171cb94e4..33adc629ec 100644 --- a/seed/challenges/basic-bonfires.json +++ b/seed/challenges/basic-bonfires.json @@ -367,6 +367,9 @@ "tests": [ "assert(repeat(\"*\", 3) === \"***\", 'message: repeat(\"*\", 3) should return \"***\".');", "assert(repeat(\"abc\", 3) === \"abcabcabc\", 'message: repeat(\"abc\", 3) should return \"abcabcabc\".');", + "assert(repeat(\"abc\", 4) === \"abcabcabcabc\", 'message: repeat(\"abc\", 4) should return \"abcabcabcabc\".');", + "assert(repeat(\"abc\", 1) === \"abc\", 'message: repeat(\"abc\", 1) should return \"abc\".');", + "assert(repeat(\"*\", 8) === \"********\", 'message: repeat(\"fcc\", 8) should return \"********\".');", "assert(repeat(\"abc\", -2) === \"\", 'message: repeat(\"abc\", -2) should return \"\".');" ], "MDNlinks": [ From 5dbfbfcf574de448ac72aefbb30813c8539d0262 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Fri, 6 Nov 2015 16:35:57 -0800 Subject: [PATCH 29/79] Add head/tail to challenge spec. Lint EVERYTHING! --- client/commonFramework.js | 52 +- client/main.js | 1054 ++++++++++--------- common/models/challenge.json | 10 + seed/challenges/basic-javascript.json | 11 +- server/boot/challenge.js | 23 +- server/views/coursewares/showBonfire.jade | 39 +- server/views/coursewares/showHTML.jade | 35 +- server/views/coursewares/showJS.jade | 33 +- server/views/coursewares/showStep.jade | 3 +- server/views/coursewares/showVideo.jade | 15 +- server/views/partials/challenge-footer.jade | 5 + server/views/partials/challenge-modals.jade | 4 - server/views/partials/scripts.jade | 1 - server/views/stories/hot-stories.jade | 3 - server/views/stories/submit-story.jade | 10 +- 15 files changed, 724 insertions(+), 574 deletions(-) create mode 100644 server/views/partials/challenge-footer.jade diff --git a/client/commonFramework.js b/client/commonFramework.js index acbe741d4b..613f644c65 100644 --- a/client/commonFramework.js +++ b/client/commonFramework.js @@ -7,23 +7,25 @@ var common = (function() { init: [] }; - common.challengeName = common.challengeName || window.challenge_Name ? - window.challenge_Name : - ''; + common.challengeName = common.challengeName || window.challenge_Name || ''; - common.challengeType = common.challengeType || window.challengeType ? - window.challengeType : - 0; + common.challengeType = common.challengeType || window.challengeType || 0; common.challengeId = common.challengeId || window.challenge_Id; - common.challengeSeed = common.challengeSeed || window.challengeSeed ? - window.challengeSeed : - []; + common.challengeSeed = common.challengeSeed || window.challengeSeed || []; - common.seed = common.challengeSeed.reduce(function(seed, line) { - return seed + line + '\n'; - }, ''); + common.head = common.head || ''; + common.tail = common.tail || ''; + + common.convertSeed = function(seedData) { + seedData = seedData || []; + return seedData.reduce(function(seed, line) { + return seed + line + '\n'; + }, ''); + }; + + common.seed = common.convertSeed(common.challengeSeed); common.replaceScriptTags = function replaceScriptTags(value) { return value @@ -482,7 +484,7 @@ var editor = (function(CodeMirror, emmetCodeMirror, common) { }(window.CodeMirror, window.emmetCodeMirror, common)); -var tests = tests || []; +var tests = common.tests || []; var libraryIncludes = "