Merge branch 'staging' into fix/update-labs
Conflicts: common/app/routes/Jobs/components/Jobs.jsx
This commit is contained in:
@ -224,8 +224,8 @@
|
||||
"no-plusplus": 0,
|
||||
|
||||
"react/display-name": 1,
|
||||
"react/jsx-boolean-value": 1,
|
||||
"react/jsx-quotes": [1, "single", "avoid-escape"],
|
||||
"react/jsx-boolean-value": [1, "always"],
|
||||
"jsx-quotes": [1, "prefer-single"],
|
||||
"react/jsx-no-undef": 1,
|
||||
"react/jsx-sort-props": 1,
|
||||
"react/jsx-uses-react": 1,
|
||||
|
18
README.md
18
README.md
@ -4,23 +4,25 @@
|
||||
|
||||
[](https://gitter.im/freecodecamp/freecodecamp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Welcome to Free Code Camp's open source codebase!
|
||||
Welcome to Free Code Camp's open source codebase and curriculum!
|
||||
=======================
|
||||
|
||||
Free Code Camp is an open-source community of busy people who learn to code and build projects for nonprofits.
|
||||
Free Code Camp is an open-source community where you learn to code and help nonprofits.
|
||||
|
||||
Our campers (students) start by working through our free, self-paced, browser-based curriculum. Next, they build several practice projects. Finally, we pair two campers together with a stakeholder from a nonprofit organization, and help them build the solution the nonprofit has requested.
|
||||
You start by working through our self-paced, browser-based full stack JavaScript curriculum.
|
||||
|
||||
After you complete the first 400 hours worth of challenges (which involves building 10 single-page apps), you'll earn your Front End Development Certification.
|
||||
|
||||
After you complete the second 400 hours worth of challenges (which involves building and deploying 5 full stack apps), you'll earn your Full Stack Development Certification.
|
||||
|
||||
Then we'll pair you with another camper, an agile project manager, and a stakeholder from a nonprofit organization. Together, you'll plan and build an app that helps that nonprofit carry out its mission more effectively.
|
||||
|
||||
**We help our campers build job-worthy portfolios of real apps used by real people, while helping nonprofits.**
|
||||
|
||||
80% of our campers are over 25, and nearly a fifth of our campers are women.
|
||||
|
||||
This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [blog](http://medium.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp).
|
||||
This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [Medium publication](http://medium.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp).
|
||||
|
||||
[Join our community here](http://www.freecodecamp.com/signin).
|
||||
|
||||
*Note: We're currently very close to moving from Express to Loopback. As such, please keep in mind that the instructions here for setting up and running the project do not directly translate to the staging branch. Additionally, the file structure is quite a bit different. As always, the staging branch is the appropriate place to branch off of to fix/add something.*
|
||||
|
||||
Wiki
|
||||
------------
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -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;
|
||||
|
@ -820,7 +820,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;
|
||||
|
1015
client/main.js
1015
client/main.js
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { createClass, PropTypes } from 'react';
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
|
||||
export default createClass({
|
||||
export default React.createClass({
|
||||
displayName: 'FlashQueue',
|
||||
|
||||
propTypes: {
|
||||
@ -9,9 +9,9 @@ export default createClass({
|
||||
},
|
||||
|
||||
renderMessages(messages) {
|
||||
return messages.map(message => {
|
||||
return messages.map(() => {
|
||||
return (
|
||||
<Alert>
|
||||
<Alert />
|
||||
);
|
||||
});
|
||||
},
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
Col,
|
||||
CollapsibleNav,
|
||||
Nav,
|
||||
NavBrand,
|
||||
Navbar,
|
||||
NavItem
|
||||
} from 'react-bootstrap';
|
||||
@ -107,11 +108,11 @@ export default React.createClass({
|
||||
const { username, points, picture } = this.props;
|
||||
return (
|
||||
<Navbar
|
||||
brand={ logoElement }
|
||||
className='nav-height'
|
||||
fixedTop={ true }
|
||||
toggleButton={ toggleButton }
|
||||
toggleNavKey={ 0 }>
|
||||
<NavBrand>{ logoElement }</NavBrand>
|
||||
<CollapsibleNav eventKey={ 0 }>
|
||||
<Nav
|
||||
className='hamburger-dropdown'
|
||||
|
@ -8,11 +8,19 @@ export default Actions({
|
||||
return { title: title + '| Free Code Camp' };
|
||||
},
|
||||
|
||||
setUser({ username, picture, progressTimestamps = [] }) {
|
||||
setUser({
|
||||
username,
|
||||
picture,
|
||||
progressTimestamps = [],
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
}) {
|
||||
return {
|
||||
username,
|
||||
picture,
|
||||
points: progressTimestamps.length
|
||||
points: progressTimestamps.length,
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -1,63 +0,0 @@
|
||||
var Action = require('thundercats').Action,
|
||||
executeBonfire = require('./executeBonfire'),
|
||||
getModel = require('../../utils/getModel'),
|
||||
debug = require('debug')('freecc:common:bonfires');
|
||||
|
||||
var BonfireActions = Action.createActions([
|
||||
'setUserCode',
|
||||
'testUserCode',
|
||||
'setResults',
|
||||
'setDisplay',
|
||||
'setBonfire',
|
||||
'getBonfire',
|
||||
'handleBonfireError',
|
||||
'openCompletionModal'
|
||||
]);
|
||||
|
||||
BonfireActions
|
||||
.getBonfire
|
||||
.subscribe(function(params) {
|
||||
var Bonfire = getModel('bonfire');
|
||||
var bonfireName = params.bonfireName ?
|
||||
params.bonfireName.replace(/\-/g, ' ') :
|
||||
'meet bonfire';
|
||||
debug('getting bonfire for: ', bonfireName);
|
||||
var regQuery = { name: { like: bonfireName, options: 'i' } };
|
||||
Bonfire.find(
|
||||
{ where: regQuery },
|
||||
function(err, bonfire) {
|
||||
if (err) {
|
||||
return debug('bonfire get err', err);
|
||||
}
|
||||
if (!bonfire || bonfire.length < 1) {
|
||||
return debug('404 no bonfire found for ', bonfireName);
|
||||
}
|
||||
bonfire = bonfire.pop();
|
||||
if (bonfire) {
|
||||
debug(
|
||||
'found bonfire %s for route %s',
|
||||
bonfire.name,
|
||||
bonfireName
|
||||
);
|
||||
}
|
||||
BonfireActions.setBonfire(bonfire);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
BonfireActions
|
||||
.testUserCode
|
||||
.subscribe(function({ userCode, tests }) {
|
||||
debug('test bonfire');
|
||||
executeBonfire(userCode, tests, function(err, { output, results }) {
|
||||
if (err) {
|
||||
debug('error running tests', err);
|
||||
return BonfireActions.setDisplay(err);
|
||||
}
|
||||
BonfireActions.setDisplay(output);
|
||||
BonfireActions.setResults(results);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = BonfireActions;
|
@ -1,67 +0,0 @@
|
||||
var BonfiresActions = require('./Actions');
|
||||
var { Store, setStateUtil } = require('thundercats');
|
||||
|
||||
var BonfiresStore = Store.create({
|
||||
|
||||
getInitialValue: function() {
|
||||
return {
|
||||
userCode: 'console.log(\'FreeCodeCamp!\')',
|
||||
difficulty: 0,
|
||||
description: [
|
||||
'default state'
|
||||
],
|
||||
tests: [],
|
||||
results: null
|
||||
};
|
||||
},
|
||||
|
||||
getOperations: function() {
|
||||
var {
|
||||
setBonfire,
|
||||
setUserCode,
|
||||
setResults,
|
||||
setDisplay
|
||||
} = BonfiresActions;
|
||||
|
||||
return [
|
||||
setBonfire
|
||||
.map(function(bonfire) {
|
||||
var {
|
||||
name,
|
||||
description,
|
||||
difficulty,
|
||||
tests
|
||||
} = bonfire;
|
||||
var userCode = bonfire.challengeSeed;
|
||||
return {
|
||||
name,
|
||||
userCode,
|
||||
tests,
|
||||
description,
|
||||
difficulty
|
||||
};
|
||||
})
|
||||
.map(setStateUtil),
|
||||
|
||||
setUserCode
|
||||
.map(function(userCode) {
|
||||
return { userCode };
|
||||
})
|
||||
.map(setStateUtil),
|
||||
|
||||
setDisplay
|
||||
.map(function(display) {
|
||||
return { display };
|
||||
})
|
||||
.map(setStateUtil),
|
||||
|
||||
setResults
|
||||
.map(function(results) {
|
||||
return { results };
|
||||
})
|
||||
.map(setStateUtil)
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = BonfiresStore;
|
@ -1,99 +0,0 @@
|
||||
var React = require('react'),
|
||||
|
||||
// ## mixins
|
||||
{ ObservableStateMixin } = require('thundercats'),
|
||||
|
||||
// ## components
|
||||
SidePanel = require('./SidePanel.jsx'),
|
||||
Results = require('./Results.jsx'),
|
||||
Display = require('../displayCode'),
|
||||
Editor = require('../editor'),
|
||||
{ Grid, Row, Col } = require('react-bootstrap'),
|
||||
|
||||
// ## flux
|
||||
BonfireActions = require('./Actions'),
|
||||
BonfireStore = require('./Store');
|
||||
|
||||
var Bonfire = React.createClass({
|
||||
|
||||
mixins: [ObservableStateMixin],
|
||||
|
||||
contextTypes: {
|
||||
makePath: React.PropTypes.func.isRequired,
|
||||
replaceWith: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
getObservable: function() {
|
||||
return BonfireStore;
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
// get history object
|
||||
var his = typeof window !== 'undefined' ? window.history : null;
|
||||
// spinal-case bonfireName
|
||||
var bonfireName = this.state.name.toLowerCase().replace(/\s/g, '-');
|
||||
// create proper URI from react-router
|
||||
var path = this.context.makePath('bonfires', { bonfireName: bonfireName });
|
||||
|
||||
// if html5 push state exists, update URI
|
||||
// else we are using hash location and should just cause a re render
|
||||
if (his) {
|
||||
his.replaceState({ path: path }, '', path);
|
||||
} else {
|
||||
this.context.replaceWith('bonfires', { bonfireName: bonfireName});
|
||||
}
|
||||
},
|
||||
|
||||
_onTestBonfire: function() {
|
||||
BonfireActions.testUserCode({
|
||||
userCode: this.state.userCode,
|
||||
tests: this.state.tests
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var {
|
||||
name,
|
||||
userCode,
|
||||
difficulty,
|
||||
description,
|
||||
results,
|
||||
display
|
||||
} = this.state;
|
||||
var brief = description.slice(0, 1).pop();
|
||||
|
||||
// convert bonfire difficulty from floating point string
|
||||
// to integer.
|
||||
var difficultyInt = Math.floor(+difficulty);
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Row>
|
||||
<Col
|
||||
xs={ 12 }
|
||||
md={ 4 }>
|
||||
<SidePanel
|
||||
name={ name }
|
||||
brief={ brief }
|
||||
difficulty={ difficultyInt }
|
||||
onTestBonfire={ this._onTestBonfire }
|
||||
description={ description.length > 1 ? description : [] }/>
|
||||
<Display
|
||||
value={ display }/>
|
||||
<Results
|
||||
results={ results }/>
|
||||
</Col>
|
||||
<Col
|
||||
xs={ 12 }
|
||||
md={ 8 }>
|
||||
<Editor
|
||||
onValueChange={ BonfireActions.setUserCode }
|
||||
value={ userCode }/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Bonfire;
|
@ -1,62 +0,0 @@
|
||||
var React = require('react'),
|
||||
classNames = require('classnames'),
|
||||
{ Grid, Row, Col } = require('react-bootstrap');
|
||||
|
||||
var Results = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
results: React.PropTypes.array
|
||||
},
|
||||
|
||||
_renderText: function(text, textClass) {
|
||||
return (
|
||||
<Col
|
||||
xs={ 11 }
|
||||
className={ classNames(textClass) }>
|
||||
{ text }
|
||||
</Col>
|
||||
);
|
||||
},
|
||||
|
||||
_renderResult: function(results) {
|
||||
return results.map(function(result, idx) {
|
||||
var err = result.err;
|
||||
var iconClass = {
|
||||
'ion-close-circled big-error-icon': err,
|
||||
'ion-checkmark-circled big-success-icon': !err
|
||||
};
|
||||
var textClass = {
|
||||
'test-output wrappable': true,
|
||||
'test-vertical-center': !err
|
||||
};
|
||||
return (
|
||||
<div key={ idx }>
|
||||
<Row>
|
||||
<Col
|
||||
xs={ 1 }
|
||||
className='text-center'>
|
||||
<i className={ classNames(iconClass) }></i>
|
||||
</Col>
|
||||
{ this._renderText(result.text, textClass) }
|
||||
{ err ? this._renderText(err, textClass) : null }
|
||||
</Row>
|
||||
<div className='ten-pixel-break'></div>
|
||||
</div>
|
||||
);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var results = this.props.results;
|
||||
if (!results || results.length && results.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Grid>
|
||||
{ this._renderResult(this.props.results) }
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Results;
|
@ -1,129 +0,0 @@
|
||||
var React = require('react'),
|
||||
|
||||
// ## components
|
||||
{
|
||||
Well,
|
||||
Row,
|
||||
Col,
|
||||
Button,
|
||||
} = require('react-bootstrap');
|
||||
|
||||
var SidePanel = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
name: React.PropTypes.string,
|
||||
brief: React.PropTypes.string,
|
||||
description: React.PropTypes.array,
|
||||
difficulty: React.PropTypes.number,
|
||||
onTestBonfire: React.PropTypes.func
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
name: 'Welcome to Bonfires!',
|
||||
difficulty: 5,
|
||||
brief: 'This is a brief description'
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
isMoreInfoOpen: false
|
||||
};
|
||||
},
|
||||
|
||||
_toggleMoreInfo: function() {
|
||||
this.setState({
|
||||
isMoreInfoOpen: !this.state.isMoreInfoOpen
|
||||
});
|
||||
},
|
||||
|
||||
_renderFlames: function() {
|
||||
var difficulty = this.props.difficulty;
|
||||
|
||||
return [1, 2, 3, 4, 5].map(num => {
|
||||
var className = 'ion-ios-flame';
|
||||
if (num > difficulty) {
|
||||
className += '-outline';
|
||||
}
|
||||
return (
|
||||
<i
|
||||
key={ num }
|
||||
className={ className }/>
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
_renderMoreInfo: function(isDescription) {
|
||||
var description = this.props.description.map((sentance, index) => {
|
||||
return <p key={ index }>{ sentance }</p>;
|
||||
});
|
||||
|
||||
if (isDescription && this.state.isMoreInfoOpen) {
|
||||
return (
|
||||
<Row>
|
||||
<Col xs={ 12 }>
|
||||
{ description }
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_renderMoreInfoButton: function(isDescription) {
|
||||
if (isDescription) {
|
||||
return (
|
||||
<Button
|
||||
onClick={ this._toggleMoreInfo }
|
||||
bsStyle='primary'
|
||||
block={ true }
|
||||
className='btn-primary-ghost'>
|
||||
<span className='ion-arrow-down-b'></span>
|
||||
More information
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var isDescription = this.props.description &&
|
||||
this.props.description.length > 1;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className='text-center'>{ this.props.name }</h1>
|
||||
<h2 className='text-center'>
|
||||
<div className='bonfire-flames'>
|
||||
Difficulty:
|
||||
{ this._renderFlames() }
|
||||
</div>
|
||||
</h2>
|
||||
<Well>
|
||||
<Row>
|
||||
<Col xs={ 12 }>
|
||||
<div className='bonfire-instructions'>
|
||||
<p>{ this.props.brief }</p>
|
||||
<div>
|
||||
{ this._renderMoreInfo(isDescription) }
|
||||
{ this._renderMoreInfoButton(isDescription) }
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Well>
|
||||
<Button
|
||||
bsStyle='primary'
|
||||
block={ true }
|
||||
className='btn-big'
|
||||
onClick={ this.props.onTestBonfire }>
|
||||
Run Code (ctrl + enter)
|
||||
</Button>
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SidePanel;
|
@ -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
|
||||
});
|
||||
});
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
/*
|
||||
export default {
|
||||
path: 'bonfires/(:bonfireName)'
|
||||
getComponents(cb) {
|
||||
// TODO(berks): add bonfire component
|
||||
}
|
||||
};
|
||||
*/
|
@ -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() {
|
||||
|
@ -38,6 +38,7 @@ export default React.createClass({
|
||||
|
||||
const className = classnames({
|
||||
'jobs-list': true,
|
||||
'col-xs-12': true,
|
||||
'jobs-list-highlight': isHighlighted
|
||||
});
|
||||
|
||||
@ -47,7 +48,7 @@ export default React.createClass({
|
||||
key={ id }
|
||||
onClick={ () => handleClick(id) }>
|
||||
<div>
|
||||
<h4 style={{ display: 'inline-block' }}>
|
||||
<h4 className='pull-left' style={{ display: 'inline-block' }}>
|
||||
<bold>{ company }</bold>
|
||||
{' '}
|
||||
<span className='hidden-xs hidden-sm'>
|
||||
|
@ -45,17 +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.
|
||||
@ -125,9 +114,9 @@ export default contain({
|
||||
url,
|
||||
logo,
|
||||
company,
|
||||
isHighlighted,
|
||||
isFrontEndCert = true,
|
||||
isFullStackCert,
|
||||
isFrontEndCert,
|
||||
isHighlighted,
|
||||
isRemoteOk,
|
||||
howToApply
|
||||
} = form;
|
||||
@ -140,10 +129,10 @@ 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))
|
||||
howToApply: formatValue(howToApply, makeRequired(isAscii)),
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
};
|
||||
},
|
||||
subscribeOnWillMount() {
|
||||
@ -163,9 +152,9 @@ export default contain({
|
||||
logo: PropTypes.object,
|
||||
company: PropTypes.object,
|
||||
isHighlighted: PropTypes.object,
|
||||
isFullStackCert: PropTypes.object,
|
||||
isFrontEndCert: PropTypes.object,
|
||||
isRemoteOk: PropTypes.object,
|
||||
isFrontEndCert: PropTypes.bool,
|
||||
isFullStackCert: PropTypes.bool,
|
||||
howToApply: PropTypes.object
|
||||
},
|
||||
|
||||
@ -173,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) {
|
||||
if (!valid || !pros.isFrontEndCert && !pros.isFullStackCert ) {
|
||||
debug('form not valid');
|
||||
return;
|
||||
}
|
||||
@ -198,9 +187,9 @@ export default contain({
|
||||
url,
|
||||
logo,
|
||||
company,
|
||||
isHighlighted,
|
||||
isFullStackCert,
|
||||
isFrontEndCert,
|
||||
isFullStackCert,
|
||||
isHighlighted,
|
||||
isRemoteOk,
|
||||
howToApply
|
||||
} = this.props;
|
||||
@ -215,10 +204,10 @@ 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)
|
||||
howToApply: inHTMLData(howToApply.value),
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
};
|
||||
|
||||
const job = Object.keys(jobValues).reduce((accu, prop) => {
|
||||
@ -245,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,
|
||||
@ -255,12 +256,13 @@ export default contain({
|
||||
logo,
|
||||
company,
|
||||
isHighlighted,
|
||||
isFrontEndCert,
|
||||
isFullStackCert,
|
||||
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';
|
||||
@ -277,7 +279,52 @@ export default contain({
|
||||
onSubmit={ this.handleSubmit }>
|
||||
|
||||
<div className='spacer'>
|
||||
<h2>First, tell us about the position</h2>
|
||||
<h2>First, select your ideal applicant: </h2>
|
||||
</div>
|
||||
|
||||
<Row>
|
||||
<Col
|
||||
xs={ 6 }
|
||||
xsOffset={ 3 }>
|
||||
<Row>
|
||||
<Button
|
||||
className={ isFrontEndCert ? 'active' : '' }
|
||||
onClick={ () => {
|
||||
if (!isFrontEndCert) {
|
||||
this.handleCertClick('isFrontEndCert');
|
||||
}
|
||||
}}>
|
||||
<h4>Front End Development Certified</h4>
|
||||
You can expect each applicant
|
||||
to have a code portfolio using the
|
||||
following technologies:
|
||||
HTML5, CSS, jQuery, API integrations
|
||||
<br />
|
||||
<br />
|
||||
</Button>
|
||||
</Row>
|
||||
<div className='button-spacer' />
|
||||
<Row>
|
||||
<Button
|
||||
className={ isFullStackCert ? 'active' : ''}
|
||||
onClick={ () => {
|
||||
if (!isFullStackCert) {
|
||||
this.handleCertClick('isFullStackCert');
|
||||
}
|
||||
}}>
|
||||
<h4>Full Stack Development Certified</h4>
|
||||
You can expect each applicant to have a code
|
||||
portfolio using the following technologies:
|
||||
HTML5, CSS, jQuery, API integrations, MVC Framework,
|
||||
JavaScript, Node.js, MongoDB, Express.js
|
||||
<br />
|
||||
<br />
|
||||
</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<div className='spacer'>
|
||||
<h2>Tell us about the position</h2>
|
||||
</div>
|
||||
<Input
|
||||
bsStyle={ position.bsStyle }
|
||||
@ -311,26 +358,6 @@ export default contain({
|
||||
type='textarea'
|
||||
value={ description.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
checked={ isFrontEndCert.value }
|
||||
label={ isFrontEndCopy }
|
||||
onChange={
|
||||
({ target: { checked } }) => handleForm({
|
||||
isFrontEndCert: !!checked
|
||||
})
|
||||
}
|
||||
type='checkbox'
|
||||
wrapperClassName={ checkboxClass } />
|
||||
<Input
|
||||
checked={ isFullStackCert.value }
|
||||
label={ isFullStackCopy }
|
||||
onChange={
|
||||
({ target: { checked } }) => handleForm({
|
||||
isFullStackCert: !!checked
|
||||
})
|
||||
}
|
||||
type='checkbox'
|
||||
wrapperClassName={ checkboxClass } />
|
||||
<Input
|
||||
checked={ isRemoteOk.value }
|
||||
label={ isRemoteCopy }
|
||||
@ -341,9 +368,6 @@ export default contain({
|
||||
}
|
||||
type='checkbox'
|
||||
wrapperClassName={ checkboxClass } />
|
||||
<Row>
|
||||
<small>* { foo }</small>
|
||||
</Row>
|
||||
<div className='spacer' />
|
||||
<Row>
|
||||
<div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { createClass } from 'react';
|
||||
import React, { PropTypes } from 'react';
|
||||
import { History } from 'react-router';
|
||||
import { contain } from 'thundercats-react';
|
||||
|
||||
@ -6,12 +6,66 @@ import ShowJob from './ShowJob.jsx';
|
||||
import JobNotFound from './JobNotFound.jsx';
|
||||
import { isJobValid } from '../utils';
|
||||
|
||||
function shouldShowApply(
|
||||
{
|
||||
isFrontEndCert: isFrontEndCertReq = false,
|
||||
isFullStackCert: isFullStackCertReq = false
|
||||
}, {
|
||||
isFrontEndCert = false,
|
||||
isFullStackCert = false
|
||||
}
|
||||
) {
|
||||
return (!isFrontEndCertReq && !isFullStackCertReq) ||
|
||||
(isFullStackCertReq && isFullStackCert) ||
|
||||
(isFrontEndCertReq && isFrontEndCert);
|
||||
}
|
||||
|
||||
function generateMessage(
|
||||
{
|
||||
isFrontEndCert: isFrontEndCertReq = false,
|
||||
isFullStackCert: isFullStackCertReq = false
|
||||
},
|
||||
{
|
||||
isFrontEndCert = false,
|
||||
isFullStackCert = false,
|
||||
isSignedIn = false
|
||||
}
|
||||
) {
|
||||
|
||||
if (!isSignedIn) {
|
||||
return 'Must be signed in to apply';
|
||||
}
|
||||
if (isFrontEndCertReq && !isFrontEndCert) {
|
||||
return 'This employer requires Free Code Camp’s Front ' +
|
||||
'End Development Certification in order to apply';
|
||||
}
|
||||
if (isFullStackCertReq && !isFullStackCert) {
|
||||
return 'This employer requires Free Code Camp’s Full ' +
|
||||
'Stack Development Certification in order to apply';
|
||||
}
|
||||
if (isFrontEndCertReq && isFrontEndCertReq) {
|
||||
return 'This employer requires the Front End Development Certification. ' +
|
||||
"You've earned it, so feel free to apply.";
|
||||
}
|
||||
return 'This employer requires the Full Stack Development Certification. ' +
|
||||
"You've earned it, so feel free to apply.";
|
||||
}
|
||||
|
||||
export default contain(
|
||||
{
|
||||
store: 'jobsStore',
|
||||
stores: ['appStore', 'jobsStore'],
|
||||
fetchWaitFor: 'jobsStore',
|
||||
fetchAction: 'jobActions.getJob',
|
||||
map({ currentJob }) {
|
||||
return { job: currentJob };
|
||||
combineLatest(
|
||||
{ username, isFrontEndCert, isFullStackCert },
|
||||
{ currentJob }
|
||||
) {
|
||||
return {
|
||||
username,
|
||||
job: currentJob,
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
};
|
||||
},
|
||||
getPayload({ params: { id }, job = {} }) {
|
||||
return {
|
||||
@ -25,9 +79,16 @@ export default contain(
|
||||
return job.id !== id;
|
||||
}
|
||||
},
|
||||
createClass({
|
||||
React.createClass({
|
||||
displayName: 'Show',
|
||||
|
||||
propTypes: {
|
||||
job: PropTypes.object,
|
||||
isFullStackCert: PropTypes.bool,
|
||||
isFrontEndCert: PropTypes.bool,
|
||||
username: PropTypes.string
|
||||
},
|
||||
|
||||
mixins: [History],
|
||||
|
||||
componentDidMount() {
|
||||
@ -39,12 +100,36 @@ export default contain(
|
||||
},
|
||||
|
||||
render() {
|
||||
const { job } = this.props;
|
||||
const {
|
||||
isFullStackCert,
|
||||
isFrontEndCert,
|
||||
job,
|
||||
username
|
||||
} = this.props;
|
||||
|
||||
if (!isJobValid(job)) {
|
||||
return <JobNotFound />;
|
||||
}
|
||||
return <ShowJob { ...this.props }/>;
|
||||
|
||||
const isSignedIn = !!username;
|
||||
|
||||
const showApply = shouldShowApply(
|
||||
job,
|
||||
{ isFrontEndCert, isFullStackCert }
|
||||
);
|
||||
|
||||
const message = generateMessage(
|
||||
job,
|
||||
{ isFrontEndCert, isFullStackCert, isSignedIn }
|
||||
);
|
||||
|
||||
return (
|
||||
<ShowJob
|
||||
message={ message }
|
||||
preview={ false }
|
||||
showApply={ showApply }
|
||||
{ ...this.props }/>
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -22,7 +22,10 @@ export default React.createClass({
|
||||
displayName: 'ShowJob',
|
||||
propTypes: {
|
||||
job: PropTypes.object,
|
||||
params: PropTypes.object
|
||||
params: PropTypes.object,
|
||||
showApply: PropTypes.bool,
|
||||
preview: PropTypes.bool,
|
||||
message: PropTypes.string
|
||||
},
|
||||
|
||||
renderHeader({ company, position }) {
|
||||
@ -38,8 +41,45 @@ export default React.createClass({
|
||||
);
|
||||
},
|
||||
|
||||
renderHowToApply(showApply, preview, message, howToApply) {
|
||||
if (!showApply) {
|
||||
return (
|
||||
<Row>
|
||||
<Col
|
||||
md={ 6 }
|
||||
mdOffset={ 3 }>
|
||||
<h4 className='bg-info text-center'>{ message }</h4>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col
|
||||
md={ 6 }
|
||||
mdOffset={ 3 }>
|
||||
<Well>
|
||||
<bold>{ preview ? 'How do I apply?' : message }</bold>
|
||||
<br />
|
||||
<br />
|
||||
<span dangerouslySetInnerHTML={{
|
||||
__html: addATags(howToApply)
|
||||
}} />
|
||||
</Well>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { job = {} } = this.props;
|
||||
const {
|
||||
showApply = true,
|
||||
message,
|
||||
preview = true,
|
||||
job = {}
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
logo,
|
||||
position,
|
||||
@ -93,20 +133,7 @@ export default React.createClass({
|
||||
<p>{ description }</p>
|
||||
</Col>
|
||||
</Row>
|
||||
<Well>
|
||||
<Row>
|
||||
<Col
|
||||
md={ 6 }
|
||||
mdOffset={ 3 }>
|
||||
<bold>How do I apply?</bold>
|
||||
<br />
|
||||
<br />
|
||||
<span dangerouslySetInnerHTML={{
|
||||
__html: addATags(howToApply)
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Well>
|
||||
{ this.renderHowToApply(showApply, preview, message, howToApply) }
|
||||
</Panel>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -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',
|
||||
|
||||
|
@ -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 (
|
||||
<form className='code'>
|
||||
<div className='form-group codeMirrorView'>
|
||||
<Tailspin
|
||||
{ ...options }
|
||||
config={ config }/>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Editor;
|
@ -1 +0,0 @@
|
||||
module.exports = require('./Display.jsx');
|
@ -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 (
|
||||
<div id='mainEditorPanel'>
|
||||
<form className='code'>
|
||||
<div className='form-group codeMirrorView'>
|
||||
<Tailspin
|
||||
{ ...options }
|
||||
config={ config }/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Editor;
|
@ -1 +0,0 @@
|
||||
module.exports = require('./Editor.jsx');
|
@ -44,6 +44,20 @@
|
||||
"tests": {
|
||||
"type": "array"
|
||||
},
|
||||
"head": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"description": "appended to user code"
|
||||
},
|
||||
"tail": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"description": "prepended to user code"
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string",
|
||||
"description": "filename challenge comes from. Used in dev mode"
|
||||
},
|
||||
"challengeSeed": {
|
||||
"type": "array"
|
||||
},
|
||||
|
19
gulpfile.js
19
gulpfile.js
@ -93,8 +93,7 @@ var paths = {
|
||||
],
|
||||
|
||||
challenges: [
|
||||
'seed/challenges/*.json',
|
||||
'seed/under-construction/*.json'
|
||||
'seed/challenges/*.json'
|
||||
]
|
||||
};
|
||||
|
||||
@ -178,7 +177,14 @@ gulp.task('sync', syncDepenedents, function() {
|
||||
});
|
||||
|
||||
gulp.task('lint-js', function() {
|
||||
return gulp.src(['public/js/lib/**/*'])
|
||||
return gulp.src([
|
||||
'common/**/*.js',
|
||||
'common/**/*.jsx',
|
||||
'client/**/*.js',
|
||||
'client/**/*.jsx',
|
||||
'server/**/*.js',
|
||||
'config/**/*.js'
|
||||
])
|
||||
.pipe(eslint())
|
||||
.pipe(eslint.format());
|
||||
});
|
||||
@ -392,10 +398,15 @@ var watchDependents = [
|
||||
'pack-watch-manifest'
|
||||
];
|
||||
|
||||
gulp.task('reload', function() {
|
||||
notify({ message: 'test changed' });
|
||||
reload();
|
||||
});
|
||||
|
||||
gulp.task('watch', watchDependents, function() {
|
||||
gulp.watch(paths.lessFiles, ['less']);
|
||||
gulp.watch(paths.js, ['js']);
|
||||
gulp.watch(paths.challenges, ['test-challenges']);
|
||||
gulp.watch(paths.challenges, ['test-challenges', 'reload']);
|
||||
gulp.watch(paths.js, ['js', 'dependents']);
|
||||
gulp.watch(paths.dependents, ['dependents']);
|
||||
gulp.watch(paths.manifest + '/*.json', ['build-manifest-watch']);
|
||||
|
@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Free Code Camp</title>
|
||||
<META http-equiv="refresh" content="1;URL=http://freecodecamp.github.io/freecodecamp/coverage/lcov-report/index.html">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
145
package.json
145
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/ 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",
|
||||
@ -26,124 +26,111 @@
|
||||
},
|
||||
"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",
|
||||
"bcrypt-nodejs": "~0.0.3",
|
||||
"accepts": "^1.3.0",
|
||||
"async": "^1.5.0",
|
||||
"babel": "5.8.29",
|
||||
"babel-core": "5.8.34",
|
||||
"babel-eslint": "^4.1.4",
|
||||
"babel-loader": "5.3.3",
|
||||
"body-parser": "^1.13.2",
|
||||
"chai-jquery": "~2.0.0",
|
||||
"cheerio": "~0.18.0",
|
||||
"chai-jquery": "^2.0.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",
|
||||
"dateformat": "~1.0.11",
|
||||
"debug": "~2.1.0",
|
||||
"dedent": "^0.4.0",
|
||||
"dotenv": "~0.4.0",
|
||||
"errorhandler": "~1.3.0",
|
||||
"es6-map": "^0.1.1",
|
||||
"compression": "^1.6.0",
|
||||
"connect-mongo": "~0.8.2",
|
||||
"cookie-parser": "^1.4.0",
|
||||
"csso": "^1.4.1",
|
||||
"dateformat": "^1.0.11",
|
||||
"debug": "^2.2.0",
|
||||
"dedent": "~0.6.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",
|
||||
"eslint-plugin-react": "^3.7.1",
|
||||
"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",
|
||||
"fetchr": "^0.5.12",
|
||||
"font-awesome": "~4.3.0",
|
||||
"forever": "~0.14.1",
|
||||
"frameguard": "^0.2.2",
|
||||
"github-api": "~0.7.0",
|
||||
"gulp": "~3.8.8",
|
||||
"gulp-eslint": "~0.9.0",
|
||||
"gulp-inject": "~1.0.2",
|
||||
"express-validator": "^2.18.0",
|
||||
"fetchr": "~0.5.12",
|
||||
"forever": "~0.15.1",
|
||||
"frameguard": "~0.2.2",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-eslint": "^1.1.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",
|
||||
"gulp-reduce-file": "0.0.1",
|
||||
"gulp-rev": "^6.0.1",
|
||||
"gulp-rev-replace": "^0.4.2",
|
||||
"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",
|
||||
"json-loader": "^0.5.2",
|
||||
"less": "~2.5.1",
|
||||
"jade": "^1.11.0",
|
||||
"json-loader": "~0.5.2",
|
||||
"less": "^2.5.1",
|
||||
"lodash": "^3.9.3",
|
||||
"loopback": "^2.22.0",
|
||||
"loopback-boot": "^2.13.0",
|
||||
"loopback-component-passport": "https://github.com/FreeCodeCamp/loopback-component-passport.git#feature/flashfailure",
|
||||
"loopback-component-passport": "^1.6.0",
|
||||
"loopback-connector-mongodb": "^1.10.0",
|
||||
"lusca": "~1.0.2",
|
||||
"method-override": "~2.3.0",
|
||||
"moment": "~2.10.2",
|
||||
"method-override": "^2.3.0",
|
||||
"moment": "^2.10.2",
|
||||
"mongodb": "^2.0.33",
|
||||
"morgan": "~1.5.0",
|
||||
"node-libs-browser": "^0.5.2",
|
||||
"node-slack": "0.0.7",
|
||||
"morgan": "^1.6.1",
|
||||
"node-uuid": "^1.4.3",
|
||||
"nodemailer": "~1.3.0",
|
||||
"nodemailer": "^1.9.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-google-oauth2": "^0.1.6",
|
||||
"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",
|
||||
"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",
|
||||
"pmx": "~0.5.5",
|
||||
"ramda": "~0.18.0",
|
||||
"react": "~0.14.2",
|
||||
"react-bootstrap": "~0.27.3",
|
||||
"react-motion": "~0.3.1",
|
||||
"react-router": "^1.0.0-rc4",
|
||||
"react-router-bootstrap": "~0.19.2",
|
||||
"react-vimeo": "~0.0.3",
|
||||
"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",
|
||||
"thundercats-react": "~0.4.0",
|
||||
"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"
|
||||
"xss-filters": "^1.2.6"
|
||||
},
|
||||
"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.12",
|
||||
"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-component-explorer": "^2.1.1",
|
||||
"loopback-testing": "^1.1.0",
|
||||
"mocha": "~2.0.1",
|
||||
"multiline": "~1.0.1",
|
||||
"supertest": "~0.15.0",
|
||||
"mocha": "^2.3.3",
|
||||
"tap-nyan": "0.0.2",
|
||||
"tape": "^4.2.2",
|
||||
"vinyl-source-stream": "^1.1.0"
|
||||
"tape": "^4.2.2"
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,8 @@
|
||||
"tests": [
|
||||
"assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4]), [3, 5, 4], 'message: <code>sym([1, 2, 3], [5, 2, 1, 4])</code> should return <code>[3, 5, 4]</code>.');",
|
||||
"assert.sameMembers(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'message: <code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should return <code>[1, 4, 5]</code>');",
|
||||
"assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'message: <code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should return <code>[1, 4, 5]</code>.');"
|
||||
"assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'message: <code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should return <code>[1, 4, 5]</code>.');",
|
||||
"assert.sameMembers(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]), [ 7, 4, 6, 2, 3 ], 'message: <code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should return <code>[ 7, 4, 6, 2, 3 ]</code>.');"
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Array.reduce()",
|
||||
|
@ -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. <br>Return to c9.io's terminal and set your GitHub remote URL: <code>git remote set-url origin</code> followed by the URL you copied from GitHub. <br>Run <code>git push origin master</code>. <br>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 @@
|
||||
"<span class='text-info'>Bonus User Story:</span> As an unauthenticated or authenticated user, I can see and vote on everyone's polls.",
|
||||
"<span class='text-info'>Bonus User Story:</span> 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.)",
|
||||
"<span class='text-info'>Bonus User Story:</span> 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: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
|
||||
"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. <br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
|
||||
],
|
||||
@ -151,8 +156,7 @@
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can add myself to a bar to indicate I am going there tonight.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can remove myself from a bar if I no longer want to go there.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As an unauthenticated user, when I login I should not have to search again.",
|
||||
"<span class='text-info'>Hint:</span> Try using the <a href='https://www.yelp.com/developers/documentation/v2/overview' target='_blank'>Yelp API</a> to find venues in the cities your users search for.",
|
||||
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
|
||||
"<span class='text-info'>Hint:</span> Try using the <a href='https://www.yelp.com/developers/documentation/v2/overview' target='_blank'>Yelp API</a> 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. <br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
|
||||
],
|
||||
@ -184,7 +188,6 @@
|
||||
"<span class='text-info'>User Story:</span> As a user, I can add new stocks by their symbol name.",
|
||||
"<span class='text-info'>User Story:</span> As a user, I can remove stocks.",
|
||||
"<span class='text-info'>Bonus User Story:</span> 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: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
|
||||
"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. <br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
|
||||
],
|
||||
@ -216,7 +219,6 @@
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can add a new book.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can update my settings to store my full name, city, and state.",
|
||||
"<span class='text-info'>Bonus User Story:</span> 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: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
|
||||
"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. <br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
|
||||
],
|
||||
@ -251,7 +253,6 @@
|
||||
"<span class='text-info'>User Story:</span> As an unauthenticated user, I can browse other users' walls of images.",
|
||||
"<span class='text-info'>Bonus User Story:</span> 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)",
|
||||
"<span class='text-info'>Hint:</span> <a href='http://masonry.desandro.com/' target='_blank'>Masonry.js</a> is a library that allows for Pinterest-style image grids.",
|
||||
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
|
||||
"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. <br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
|
||||
],
|
||||
|
@ -325,16 +325,17 @@
|
||||
"tests": [
|
||||
"assert(end(\"Bastian\", \"n\") === true, 'message: <code>end(\"Bastian\", \"n\")</code> should return true.');",
|
||||
"assert(end(\"Connor\", \"n\") === false, 'message: <code>end(\"Connor\", \"n\")</code> should return false.');",
|
||||
"assert(end(\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\") === false, '<code>\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\")</code> should return false.');",
|
||||
"assert(end(\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\") === false, 'message: <code>end(\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\")</code> should return false.');",
|
||||
"assert(end(\"He has to give me a new name\", \"name\") === true, 'message: <code>end(\"He has to give me a new name\", \"name\")</code> should return true.');",
|
||||
"assert(end(\"He has to give me a new name\", \"me\") === true, 'message: <code>end(\"He has to give me a new name\", \"me\")</code> should return true.');",
|
||||
"assert(end(\"He has to give me a new name\", \"na\") === false, 'message: <code>end(\"He has to give me a new name\", \"na\")</code> should return false.');",
|
||||
"assert(end(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\") === false, 'message: <code>end(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\")</code> should return false.');"
|
||||
],
|
||||
"MDNlinks": [
|
||||
"String.substr()"
|
||||
],
|
||||
"solutions": [
|
||||
"function end(str, target) {\n // \"Never give up and good luck will find you.\"\n // -- Falcor\n return str.substring(str.length-target.length) === target;\n}\n\nend('Bastian', 'n');\n"
|
||||
"function end(str, target) {\n return str.substring(str.length-target.length) === target;\n};\n"
|
||||
],
|
||||
"type": "bonfire",
|
||||
"challengeType": 5,
|
||||
@ -367,6 +368,9 @@
|
||||
"tests": [
|
||||
"assert(repeat(\"*\", 3) === \"***\", 'message: <code>repeat(\"*\", 3)</code> should return <code>\"***\"</code>.');",
|
||||
"assert(repeat(\"abc\", 3) === \"abcabcabc\", 'message: <code>repeat(\"abc\", 3)</code> should return <code>\"abcabcabc\"</code>.');",
|
||||
"assert(repeat(\"abc\", 4) === \"abcabcabcabc\", 'message: <code>repeat(\"abc\", 4)</code> should return <code>\"abcabcabcabc\"</code>.');",
|
||||
"assert(repeat(\"abc\", 1) === \"abc\", 'message: <code>repeat(\"abc\", 1)</code> should return <code>\"abc\"</code>.');",
|
||||
"assert(repeat(\"*\", 8) === \"********\", 'message: <code>repeat(\"*\", 8)</code> should return <code>\"********\"</code>.');",
|
||||
"assert(repeat(\"abc\", -2) === \"\", 'message: <code>repeat(\"abc\", -2)</code> should return <code>\"\"</code>.');"
|
||||
],
|
||||
"MDNlinks": [
|
||||
@ -410,12 +414,14 @@
|
||||
"assert(truncate(\"Peter Piper picked a peck of pickled peppers\", 14) === \"Peter Piper...\", 'message: <code>truncate(\"Peter Piper picked a peck of pickled peppers\", 14)</code> 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: <code>truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length)</code> 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: <code>truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length + 2)</code> should return \"A-tisket a-tasket A green and yellow basket\".');",
|
||||
"assert(truncate(\"A-\", 1) === \"A...\", 'message: <code>truncate(\"A-\", 1)</code> should return \"A...\".');"
|
||||
"assert(truncate(\"A-\", 1) === \"A...\", 'message: <code>truncate(\"A-\", 1)</code> should return \"A...\".');",
|
||||
"assert(truncate(\"Abolutely Longer\", 2) === \"Ab...\", 'message: <code>truncate(\"Absolutely Longer\", 2)</code> 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,
|
||||
|
@ -7,7 +7,7 @@
|
||||
"id": "bd7123c9c441eddfaeb4bdef",
|
||||
"title": "Comment your JavaScript Code",
|
||||
"description": [
|
||||
"Comments are lines of code that your computer will intentionally ignore. Comments are a great way to leave notes to yourself and to other people who will later need to figure out what it does.",
|
||||
"Comments are lines of code that your computer will intentionally ignore. Comments are a great way to leave notes to yourself and to other people who will later need to figure out what that code does.",
|
||||
"Let's take a look at the two ways you can write comments in JavaScript.",
|
||||
"The double-slash comment will comment out the remainder of the text on the current line:",
|
||||
"<code>// This is a comment.</code>",
|
||||
@ -30,7 +30,7 @@
|
||||
"description": [
|
||||
"In computer science, <code>data structures</code> are things that hold data. JavaScript has seven of these. For example, the <code>Number</code> data structure holds numbers.",
|
||||
"Let's learn about the most basic data structure of all: the <code>Boolean</code>. Booleans can only hold the value of either true or false. They are basically little on-off switches.",
|
||||
"Let's modify our <code>welcomeToBooleans</code> function so that it will return <code>true</code> instead of <code>false</code>when the run button is clicked."
|
||||
"Let's modify our <code>welcomeToBooleans</code> function so that it will return <code>true</code> instead of <code>false</code> when the run button is clicked."
|
||||
],
|
||||
"tests": [
|
||||
"assert(typeof(welcomeToBooleans()) === 'boolean', 'message: The <code>welcomeToBooleans()</code> function should return a boolean (true/false) value.');",
|
||||
@ -44,8 +44,9 @@
|
||||
" return false;",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"}",
|
||||
"",
|
||||
"}"
|
||||
],
|
||||
"tail": [
|
||||
"welcomeToBooleans();"
|
||||
],
|
||||
"type": "waypoint",
|
||||
@ -67,9 +68,9 @@
|
||||
"challengeSeed": [
|
||||
"var ourName = \"Free Code Camp\";",
|
||||
"",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
""
|
||||
],
|
||||
"tail": [
|
||||
"if(typeof(myName) !== \"undefined\"){(function(v){return v;})(myName);}"
|
||||
],
|
||||
"type": "waypoint",
|
||||
@ -87,7 +88,6 @@
|
||||
"assert((function(){if(typeof(myLastName) !== \"undefined\" && typeof(myLastName) === \"string\" && myLastName.length > 0){return true;}else{return false;}})(), 'message: <code>myLastName</code> should be a string with at least one character in it.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var name = \"Alan Turing\";",
|
||||
"var firstName = \"Alan\";",
|
||||
"var lastName = \"Turing\";",
|
||||
"",
|
||||
@ -140,11 +140,11 @@
|
||||
"<code>Bracket notation</code> is a way to get a character at a specific <code>index</code> within a string.",
|
||||
"Computers don't start counting at 1 like humans do. They start at 0.",
|
||||
"For example, the character at index 0 in the word \"Charles\" is \"C\". So if <code>var firstName = \"Charles\"</code>, you can get the value of the first letter of the string by using <code>firstName[0]</code>.",
|
||||
"Use <code>bracket notation</code> to find the first character in the <code>firstLetterOfLastName</code> variable.",
|
||||
"Use <code>bracket notation</code> to find the first character in the <code>lastName</code> variable and assign it to <code>firstLetterOfLastName</code>.",
|
||||
"Try looking at the <code>firstLetterOfFirstName</code> variable declaration if you get stuck."
|
||||
],
|
||||
"tests": [
|
||||
"assert((function(){if(typeof(firstLetterOfLastName) !== \"undefined\" && editor.getValue().match(/\\[0\\]/gi) && typeof(firstLetterOfLastName) === \"string\" && firstLetterOfLastName === \"L\"){return true;}else{return false;}})(), 'message: The first letter of <code>firstLetterOfLastName</code> should be a <code>\"L\"</code>.');"
|
||||
"assert((function(){if(typeof(firstLetterOfLastName) !== \"undefined\" && editor.getValue().match(/\\[0\\]/gi) && typeof(firstLetterOfLastName) === \"string\" && firstLetterOfLastName === \"L\"){return true;}else{return false;}})(), 'message: The <code>firstLetterOfLastName</code> variable should have the value of <code>L</code>.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var firstLetterOfFirstName = \"\";",
|
||||
@ -176,7 +176,7 @@
|
||||
"Try looking at the <code>secondLetterOfFirstName</code> variable declaration if you get stuck."
|
||||
],
|
||||
"tests": [
|
||||
"assert(thirdLetterOfLastName === 'v', 'message: The third letter of <code>lastName</code> should be a \"v\".');"
|
||||
"assert(thirdLetterOfLastName === 'v', 'message: The <code>thirdLetterOfLastName</code> variable should have the value of <code>v</code>.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var firstName = \"Ada\";",
|
||||
@ -229,7 +229,7 @@
|
||||
"id": "bd7123c9c452eddfaeb5bdef",
|
||||
"title": "Use Bracket Notation to Find the Nth-to-Last Character in a String",
|
||||
"description": [
|
||||
"In order to get the last letter of a string, you can subtract one from the string's length.",
|
||||
"You can use the same principle we just used to retrieve the last character in a string to retrieve the Nth-to-last character.",
|
||||
"For example, you can get the value of the third-to-last letter of the <code>var firstName = \"Charles\"</code> string by using <code>firstName[firstName.length - 3]</code>",
|
||||
"Use <code>bracket notation</code> to find the second-to-last character in the <code>lastName</code> string.",
|
||||
"Try looking at the <code>thirdToLastLetterOfFirstName</code> variable declaration if you get stuck."
|
||||
@ -524,7 +524,7 @@
|
||||
"title": "Manipulate Arrays With pop()",
|
||||
"description": [
|
||||
"Another way to change the data in an array is with the <code>.pop()</code> function.",
|
||||
"<code>.pop()</code>is used to \"pop\" a value off of the end of an array. We can store this \"popped off\" variable by performing <code>pop()</code> within a variable declaration.",
|
||||
"<code>.pop()</code> is used to \"pop\" a value off of the end of an array. We can store this \"popped off\" variable by performing <code>pop()</code> within a variable declaration.",
|
||||
"Any type of data structure can be \"popped\" off of an array - numbers, strings, even nested arrays.",
|
||||
"Use the <code>.pop()</code> function to remove the last item from <code>myArray</code>, assigning the \"popped off\" value to <code>removedFromMyArray</code>."
|
||||
],
|
||||
@ -545,7 +545,7 @@
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
"(function(y, z){return 'removedFromMyArray = ' + JSON.stringify(y) + ' & removed = ' + JSON.stringify(z);})(myArray, removedFromMyArray);"
|
||||
"(function(y, z){return 'myArray = ' + JSON.stringify(y) + ' & removedFromMyArray = ' + JSON.stringify(z);})(myArray, removedFromMyArray);"
|
||||
],
|
||||
"type": "waypoint",
|
||||
"challengeType": 1
|
||||
@ -661,7 +661,7 @@
|
||||
"Create and call a function called <code>myFunction</code> that returns the sum of <code>a</code> and <code>b</code>."
|
||||
],
|
||||
"tests": [
|
||||
"assert((function(){if(typeof(f) !== \"undefined\" && f === a + b){return true;}else{return false;}})(), 'message: Your function should return the value of a + b');"
|
||||
"assert((function(){if(typeof(f) !== \"undefined\" && f === a + b){return true;}else{return false;}})(), 'message: Your function should return the value of <code>a + b</code>.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var a = 4;",
|
||||
@ -752,7 +752,7 @@
|
||||
"Let's update the <code>myDog</code> object's name property. Let's change her name from \"Coder\" to \"Happy Coder\"."
|
||||
],
|
||||
"tests": [
|
||||
"assert(/happy coder/gi.test(myDog.name), 'message: Update <code>myDog</code>\\'s <code>\"name\"</code> property to equal \"Happy Coder\".');"
|
||||
"assert(/happy coder/gi.test(myDog.name), 'message: Update <code>myDog</code>'s <code>\"name\"</code> property to equal \"Happy Coder\".');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var ourDog = {",
|
||||
@ -771,6 +771,10 @@
|
||||
" \"friends\": [\"Free Code Camp Campers\"]",
|
||||
"};",
|
||||
"",
|
||||
"// Only change code below this line.",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
"(function(z){return z;})(myDog);"
|
||||
@ -867,26 +871,26 @@
|
||||
"You can run the same code multiple times by using a loop.",
|
||||
"The most common type of JavaScript loop is called a \"for loop\" because it runs \"for\" a specific number of times.",
|
||||
"For loops are declared with three optional expressions seperated by semicolons:",
|
||||
"<code>for([initialization]; [condition]; [final-expression])</code>",
|
||||
"<code>for ([initialization]; [condition]; [final-expression])</code>",
|
||||
"The <code>initialization</code> statement is executed one time only before the loop starts. It is typically used to define and setup your loop variable.",
|
||||
"The <code>condition</code> statement is evaluated at the beginning of every loop iteration and will continue as long as it evalutes to <code>true</code>. When <code>condition</code> is <code>false</code> at the start of the iteration, the loop will stop executing. This means if <code>condition</code> starts as <code>false</code>, your loop will never execute.",
|
||||
"The <code>final-expression</code> is executed at the end of each loop iteration, prior to the next <code>condition</code> check and is usually used to increment or decrement your loop counter.",
|
||||
"In the following example we initialize with <code>i = 0</code> and iterate while our condition <code>i < 5</code> is true. We'll increment <code>i</code> by <code>1</code> in each loop iteration with <code>i++</code> as our <code>final-expression</code>.",
|
||||
"<code>var ourArray = [];</code>",
|
||||
"<code>for(var i = 0; i < 5; i++) {</code>",
|
||||
"<code>for (var i = 0; i < 5; i++) {</code>",
|
||||
"<code> ourArray.push(i);</code>",
|
||||
"<code>}</code>",
|
||||
"<code>ourArray</code> will now contain <code>[0,1,2,3,4]</code>.",
|
||||
"Let's try getting a <code>for</code> loop to work by pushing values to an array."
|
||||
"Let's use a <code>for</code> loop to work to push the values 1 through 5 onto <code>myArray</code>."
|
||||
],
|
||||
"tests": [
|
||||
"assert(editor.getValue().match(/for\\s*\\(/g).length > 1, 'message: You should be using a <code>for</code> loop for this.');",
|
||||
"assert.deepEqual(myArray, [0,1,2,3,4], 'message: <code>myArray</code> should equal <code>[0,1,2,3,4]</code>');"
|
||||
"assert.deepEqual(myArray, [1,2,3,4,5], 'message: <code>myArray</code> should equal <code>[1,2,3,4,5]</code>.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var ourArray = [];",
|
||||
"",
|
||||
"for(var i = 0; i < 5; i++){",
|
||||
"for (var i = 0; i < 5; i++) {",
|
||||
" ourArray.push(i);",
|
||||
"}",
|
||||
"",
|
||||
@ -911,21 +915,21 @@
|
||||
"For loops don't have to iterate one at a time. By changing our <code>final-expression</code>, we can count by even numbers.",
|
||||
"We'll start at <code>i = 0</code> and loop while <code>i < 10</code>. We'll increment <code>i</code> by 2 each loop with <code>i += 2</code>.",
|
||||
"<code>var ourArray = [];</code>",
|
||||
"<code>for(var i = 0; i < 10; i += 2) {</code>",
|
||||
"<code>for (var i = 0; i < 10; i += 2) {</code>",
|
||||
"<code> ourArray.push(i);</code>",
|
||||
"<code>}</code>",
|
||||
"<code>ourArray</code> will now contain [0,2,4,6,8] ",
|
||||
"<code>ourArray</code> will now contain <code>[0,2,4,6,8]</code>.",
|
||||
"Let's change our <code>initialization</code> and <code>final-expression</code> so we can count by odd numbers.",
|
||||
"Push the odd numbers from 1 through 9 to <code>myArray</code> using a <code>for loop</code>."
|
||||
"Push the odd numbers from 1 through 9 to <code>myArray</code> using a <code>for</code> loop."
|
||||
],
|
||||
"tests":[
|
||||
"assert(editor.getValue().match(/for\\s*\\(/g).length > 1, 'message: You should be using a <code>for</code> loop for this.');",
|
||||
"assert.deepEqual(myArray, [1,3,5,7,9], 'message: <code>myArray</code> should equal <code>[1,3,5,7,9]</code>');"
|
||||
"assert.deepEqual(myArray, [1,3,5,7,9], 'message: <code>myArray</code> should equal <code>[1,3,5,7,9]</code>.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var ourArray = [];",
|
||||
"",
|
||||
"for(var i = 0; i < 10; i += 2){",
|
||||
"for (var i = 0; i < 10; i += 2) {",
|
||||
" ourArray.push(i);",
|
||||
"}",
|
||||
"",
|
||||
@ -951,21 +955,21 @@
|
||||
"In order to count backwards by twos, we'll need to change our <code>initialization</code>, <code>condition</code>, and <code>final-expression</code>.",
|
||||
"We'll start at <code>i = 10</code> and loop while <code>i > 0</code>. We'll decrement <code>i</code> by 2 each loop with <code>i -= 2</code>.",
|
||||
"<code>var ourArray = [];</code>",
|
||||
"<code>for(var i = 10; i > 0; i -= 2) {</code>",
|
||||
"<code>for (var i = 10; i > 0; i -= 2) {</code>",
|
||||
"<code> ourArray.push(i);</code>",
|
||||
"<code>}</code>",
|
||||
"<code>ourArray</code> will now contain <code>[10,8,6,4,2]</code>",
|
||||
"<code>ourArray</code> will now contain <code>[10,8,6,4,2]</code>.",
|
||||
"Let's change our <code>initialization</code> and <code>final-expression</code> so we can count backward by twos for numbers.",
|
||||
"Push the odd numbers from 9 through 1 to <code>myArray</code> using a <code>for loop</code>."
|
||||
"Push the odd numbers from 9 through 1 to <code>myArray</code> using a <code>for</code> loop."
|
||||
],
|
||||
"tests":[
|
||||
"assert(editor.getValue().match(/for\\s*\\(/g).length > 1, 'message: You should be using a <code>for</code> loop for this.');",
|
||||
"assert.deepEqual(myArray, [9,7,5,3,1], 'message: <code>myArray</code> should equal <code>[9,7,5,3,1]</code>');"
|
||||
"assert.deepEqual(myArray, [9,7,5,3,1], 'message: <code>myArray</code> should equal <code>[9,7,5,3,1]</code>.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var ourArray = [];",
|
||||
"",
|
||||
"for(var i = 10; i > 0; i -= 2){",
|
||||
"for (var i = 10; i > 0; i -= 2) {",
|
||||
" ourArray.push(i);",
|
||||
"}",
|
||||
"",
|
||||
@ -996,11 +1000,11 @@
|
||||
"<code> i++;</code>",
|
||||
"<code>}</code>",
|
||||
"Let's try getting a while loop to work by pushing values to an array.",
|
||||
"Push the numbers 0 through 4 to <code>myArray</code> using a <code>while loop</code>."
|
||||
"Push the numbers 0 through 4 to <code>myArray</code> using a <code>while</code> loop."
|
||||
],
|
||||
"tests": [
|
||||
"assert(editor.getValue().match(/while/g), 'message: You should be using a <code>while</code> loop for this.');",
|
||||
"assert.deepEqual(myArray, [0,1,2,3,4], 'message: <code>myArray</code> should equal <code>[0,1,2,3,4]</code>');"
|
||||
"assert.deepEqual(myArray, [0,1,2,3,4], 'message: <code>myArray</code> should equal <code>[0,1,2,3,4]</code>.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var myArray = [];",
|
||||
@ -1062,23 +1066,24 @@
|
||||
"Let's use this technique to generate and return a random whole number between 0 and 9."
|
||||
],
|
||||
"tests": [
|
||||
"assert(typeof(myFunction()) === \"number\", 'message: The result of <code>myFunction</code> should be a number.');",
|
||||
"assert(editor.getValue().match(/Math.random/g), 'message: You should be using Math.random to generate a random number.');",
|
||||
"assert(typeof(myFunction()) === \"number\" && (function(){var r = myFunction();return Math.floor(r) === r;})(), 'message: The result of <code>myFunction</code> should be a whole number.');",
|
||||
"assert(editor.getValue().match(/Math.random/g).length > 1, 'message: You should be using <code>Math.random</code> to generate a random number.');",
|
||||
"assert(editor.getValue().match(/\\(\\s*?Math.random\\s*?\\(\\s*?\\)\\s*?\\*\\s*?10\\s*?\\)/g) || editor.getValue().match(/\\(\\s*?10\\s*?\\*\\s*?Math.random\\s*?\\(\\s*?\\)\\s*?\\)/g), 'message: You should have multiplied the result of <code>Math.random</code> by 10 to make it a number that is between zero and nine.');",
|
||||
"assert(editor.getValue().match(/Math.floor/g), 'message: You should use <code>Math.floor</code> to remove the decimal part of the number.');"
|
||||
"assert(editor.getValue().match(/Math.floor/g).length > 1, 'message: You should use <code>Math.floor</code> to remove the decimal part of the number.');"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var randomNumberBetween0and19 = Math.floor(Math.random() * 20);",
|
||||
"",
|
||||
"function myFunction(){",
|
||||
"function myFunction() {",
|
||||
"",
|
||||
" // Only change code below this line.",
|
||||
"",
|
||||
" return Math.random();",
|
||||
"",
|
||||
" // Only change code above this line.",
|
||||
"}",
|
||||
"",
|
||||
"}"
|
||||
],
|
||||
"tail":[
|
||||
"(function(){return myFunction();})();"
|
||||
],
|
||||
"type": "waypoint",
|
||||
@ -1092,7 +1097,7 @@
|
||||
"To do this, we'll define a minimum number <code>min</code> and a maximum number <code>max</code>.",
|
||||
"Here's the formula we'll use. Take a moment to read it and try to understand what this code is doing:",
|
||||
"<code>Math.floor(Math.random() * (max - min + 1)) + min</code>",
|
||||
"Define two variables: <code>myMin</code> and </code>myMax</code>, and set them both equal to numbers.",
|
||||
"Define two variables: <code>myMin</code> and <code>myMax</code>, and set them both equal to numbers.",
|
||||
"Then create a function called <code>myFunction</code> that returns a random number that's greater than or equal to <code>myMin</code>, and is less than or equal to <code>myMax</code>."
|
||||
],
|
||||
"tests": [
|
||||
@ -1211,7 +1216,7 @@
|
||||
"title": "Find Numbers with Regular Expressions",
|
||||
"description": [
|
||||
"We can use special selectors in <code>Regular Expressions</code> to select a particular type of value.",
|
||||
"One such selector is the digit selector <code>\\d</code> which is used to grab the numbers in a string.",
|
||||
"One such selector is the digit selector <code>\\d</code> which is used to retrieve the numbers in a string.",
|
||||
"It is used like this: <code>/\\d/g</code>.",
|
||||
"For numbers this is often written as <code>/\\d+/g</code>, where the <code>+</code> following the digit selector allows this regular expression to match multi-digit numbers.",
|
||||
"Use the <code>\\d</code> selector to select the number of numbers in the string, allowing for the possibility of multi-digit numbers."
|
||||
@ -1315,7 +1320,7 @@
|
||||
],
|
||||
"challengeSeed": [
|
||||
"fccss",
|
||||
" function runSlots(){",
|
||||
" function runSlots() {",
|
||||
" var slotOne;",
|
||||
" var slotTwo;",
|
||||
" var slotThree;",
|
||||
@ -1331,14 +1336,14 @@
|
||||
" $(\".logger\").html(\"\");",
|
||||
" $(\".logger\").html(\"Not A Win\")",
|
||||
" ",
|
||||
" if(slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined){",
|
||||
" if (slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined) {",
|
||||
" $(\".logger\").html(slotOne + \" \" + slotTwo + \" \" + slotThree);",
|
||||
" }",
|
||||
" return [slotOne, slotTwo, slotThree];",
|
||||
" }",
|
||||
"",
|
||||
" $(document).ready(function(){",
|
||||
" $(\".go\").click(function(){",
|
||||
" $(document).ready(function() {",
|
||||
" $(\".go\").click(function() {",
|
||||
" runSlots();",
|
||||
" });",
|
||||
" });",
|
||||
@ -1459,7 +1464,7 @@
|
||||
"Otherwise, we should return <code>null</code>, which is a JavaScript data structure that means nothing.",
|
||||
"If all three numbers match, we should return the number that we have in three of slots or leave it as <code>null</code>.",
|
||||
"Let's create an <code>if statement</code> with multiple conditions in order to check whether all numbers are equal.",
|
||||
"<code>if(slotOne !== slotTwo || slotTwo !== slotThree){</code>",
|
||||
"<code>if (slotOne !== slotTwo || slotTwo !== slotThree) {</code>",
|
||||
"<code> return null;</code>",
|
||||
"<code>}</code>"
|
||||
],
|
||||
@ -1468,7 +1473,7 @@
|
||||
],
|
||||
"challengeSeed": [
|
||||
"fccss",
|
||||
" function runSlots(){",
|
||||
" function runSlots() {",
|
||||
" var slotOne;",
|
||||
" var slotTwo;",
|
||||
" var slotThree;",
|
||||
@ -1480,7 +1485,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.",
|
||||
" ",
|
||||
@ -1488,7 +1493,7 @@
|
||||
" ",
|
||||
" // Only change code above this line.",
|
||||
" ",
|
||||
" if(slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined){",
|
||||
" if (slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined) {",
|
||||
" $(\".logger\").html(slotOne);",
|
||||
" $(\".logger\").append(\" \" + slotTwo);",
|
||||
" $(\".logger\").append(\" \" + slotThree);",
|
||||
@ -1496,8 +1501,8 @@
|
||||
" return [slotOne, slotTwo, slotThree];",
|
||||
" }",
|
||||
"",
|
||||
" $(document).ready(function(){",
|
||||
" $(\".go\").click(function(){",
|
||||
" $(document).ready(function() {",
|
||||
" $(\".go\").click(function() {",
|
||||
" runSlots();",
|
||||
" });",
|
||||
" });",
|
||||
@ -1626,7 +1631,7 @@
|
||||
],
|
||||
"challengeSeed": [
|
||||
"fccss",
|
||||
" function runSlots(){",
|
||||
" function runSlots() {",
|
||||
" var slotOne;",
|
||||
" var slotTwo;",
|
||||
" var slotThree;",
|
||||
@ -1650,7 +1655,7 @@
|
||||
" return slotOne;",
|
||||
" }",
|
||||
" ",
|
||||
" if(slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined){",
|
||||
" if (slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined) {",
|
||||
" $(\".logger\").html(slotOne);",
|
||||
" $(\".logger\").append(\" \" + slotTwo);",
|
||||
" $(\".logger\").append(\" \" + slotThree);",
|
||||
@ -1659,8 +1664,8 @@
|
||||
" return [slotOne, slotTwo, slotThree];",
|
||||
" }",
|
||||
"",
|
||||
" $(document).ready(function(){",
|
||||
" $(\".go\").click(function(){",
|
||||
" $(document).ready(function() {",
|
||||
" $(\".go\").click(function() {",
|
||||
" runSlots();",
|
||||
" });",
|
||||
" });",
|
||||
@ -1785,7 +1790,7 @@
|
||||
"Set up all three slots like this, then click the \"Go\" button to play the slot machine."
|
||||
],
|
||||
"tests": [
|
||||
"assert((editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)\\.html\\(\\s*?\\'\\<img\\s?src\\s?=\\s?\"\\'\\s?\\+\\s?images\\[\\w+\\-1\\]\\s?\\+\\s?\\'\"\\>\\'\\s*?\\);/gi) && editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)\\.html\\(\\s*?\\'\\<img\\s?src\\s?=\\s?\"\\'\\s?\\+\\s?images\\[\\w+\\-1\\]\\s?\\+\\s?\\'\"\\>\\'\\s*?\\);/gi).length >= 3), 'Use the provided code three times. One for each slot.')",
|
||||
"assert((editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)\\.html\\(\\s*?\\'\\<img\\s?src\\s?=\\s?\"\\'\\s?\\+\\s?images\\[\\w+\\s*\\-\\s*1\\]\\s?\\+\\s?\\'\"\\>\\'\\s*?\\);/gi) && editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)\\.html\\(\\s*?\\'\\<img\\s?src\\s?=\\s?\"\\'\\s?\\+\\s?images\\[\\w+\\s*\\-\\s*1\\]\\s?\\+\\s?\\'\"\\>\\'\\s*?\\);/gi).length >= 3), 'Use the provided code three times. One for each slot.')",
|
||||
"assert(editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[0\\]\\s*?\\)/gi), 'You should have used <code>$('.slot')[0]</code> at least once.')",
|
||||
"assert(editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[1\\]\\s*?\\)/gi), 'You should have used <code>$('.slot')[1]</code> at least once.')",
|
||||
"assert(editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[2\\]\\s*?\\)/gi), 'You should have used <code>$('.slot')[2]</code> at least once.')",
|
||||
@ -1795,7 +1800,7 @@
|
||||
],
|
||||
"challengeSeed": [
|
||||
"fccss",
|
||||
" function runSlots(){",
|
||||
" function runSlots() {",
|
||||
" var slotOne;",
|
||||
" var slotTwo;",
|
||||
" var slotThree;",
|
||||
@ -1819,7 +1824,7 @@
|
||||
" return slotOne;",
|
||||
" }",
|
||||
" ",
|
||||
" if(slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined){",
|
||||
" if (slotOne !== undefined && slotTwo !== undefined && slotThree !== undefined) {",
|
||||
" $('.logger').html(slotOne);",
|
||||
" $('.logger').append(' ' + slotTwo);",
|
||||
" $('.logger').append(' ' + slotThree);",
|
||||
@ -1828,8 +1833,8 @@
|
||||
" return [slotOne, slotTwo, slotThree];",
|
||||
" }",
|
||||
"",
|
||||
" $(document).ready(function(){",
|
||||
" $('.go').click(function(){",
|
||||
" $(document).ready(function() {",
|
||||
" $('.go').click(function() {",
|
||||
" runSlots();",
|
||||
" });",
|
||||
" });",
|
||||
|
@ -1674,11 +1674,12 @@
|
||||
"title": "Create a Bootstrap Row",
|
||||
"description": [
|
||||
"Now we'll create a Bootstrap row for our inline elements.",
|
||||
"Create a <code>div</code> element with the class <code>row</code>."
|
||||
"Create a <code>div</code> element below the <code>h3</code> tag, with a class of <code>row</code>."
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"div\").length > 1, 'Add a <code>div</code> element below your <code>h3</code> element.')",
|
||||
"assert($(\"div\").hasClass(\"row\"), 'Your <code>div</code> element should have the class <code>row</code>')",
|
||||
"assert($(\"div.container-fluid div.row\").length > 0, 'Your <code>row div</code> should be nested inside the <code>container-fluid div</code>')",
|
||||
"assert(editor.match(/<\\/div>/g) && editor.match(/<div/g) && editor.match(/<\\/div>/g).length === editor.match(/<div/g).length, 'Make sure your <code>div</code> element has a closing tag.')"
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
@ -557,16 +557,15 @@
|
||||
"Font size is controlled by the <code>font-size</code> CSS property, like this:",
|
||||
"<code>h1 {</code>",
|
||||
"<code> font-size: 30px;</code>",
|
||||
"}</code>",
|
||||
"See if you can figure out how to give both of your <code>p</code> elements the font-size of 16 pixels (<code>16px</code>). You can do this inside the same <code><style></code> tag that we created for your <code>red-text</code> class.",
|
||||
"<code>}</code>",
|
||||
"Create a second <code>p</code> element with the following kitty ipsum text: <code>Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.</code>",
|
||||
"Then, inside your <code><style></code> element, set the <code>font-size</code> of all <code>p</code> elements to 16 pixels."
|
||||
"Inside the same <code><style></code> tag that we created for your <code>red-text</code> class, set the <code>font-size</code> of all <code>p</code> elements to 16 pixels (<code>16px</code>)."
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"p\").length > 1, 'You need 2 <code>p</code> elements with Kitty Ipsum text.')",
|
||||
"assert(editor.match(/<\\/p>/g) && editor.match(/<\\/p>/g).length === editor.match(/<p/g).length, 'Make sure each of your <code>p</code> elements has a closing tag.')",
|
||||
"assert.isTrue((/Purr\\s+jump\\s+eat/gi).test($(\"p\").text()), 'Your <code>p</code> element should contain the first few words of the provided additional <code>kitty ipsum text</code>.')",
|
||||
"assert($(\"p\").css(\"font-size\") === \"16px\", 'Give elements with the <code>red-text</code> class a <code>font-size</code> of 16px.')"
|
||||
"assert($(\"p\").css(\"font-size\") === \"16px\", 'Give elements with the <code>p</code> tag a <code>font-size</code> of <code>16px</code>.')"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"<style>",
|
||||
@ -905,7 +904,7 @@
|
||||
"tests": [
|
||||
"assert($(\"img\").hasClass(\"smaller-image\"), 'Your <code>img</code> element should have the class <code>smaller-image</code>.')",
|
||||
"assert($(\"img\").hasClass(\"thick-green-border\"), 'Your <code>img</code> element should have the class <code>thick-green-border</code>.')",
|
||||
"assert($(\"img\").hasClass(\"thick-green-border\") && parseInt($(\"img\").css(\"border-top-width\"), 10) === 10, 'Give your image a border width of <code>10px</code>.')",
|
||||
"assert($(\"img\").hasClass(\"thick-green-border\") && parseInt($(\"img\").css(\"border-top-width\"), 10) >= 8 && parseInt($(\"img\").css(\"border-top-width\"), 10) <= 12, 'Give your image a border width of <code>10px</code>.')",
|
||||
"assert($(\"img\").css(\"border-right-style\") === \"solid\", 'Give your image a border style of <code>solid</code>.')",
|
||||
"assert($(\"img\").css(\"border-left-color\") === \"rgb(0, 128, 0)\", 'The border around your <code>img</code> element should be green.')"
|
||||
],
|
||||
@ -1168,7 +1167,7 @@
|
||||
"Now nest your existing <code>a</code> element within a new <code>p</code> element so that the surrounding paragraph says \"View more cat photos\", but where only \"cat photos\" is a link, and the rest of the text is plain text."
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"a\").attr(\"href\").match(/freecatphotoapp.com/gi).length > 0, 'You need an <code>a</code> element that links to \"freecatphotoapp.com\".')",
|
||||
"assert($(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").length > 0, 'You need an <code>a</code> element that links to \"http://www.freecatphotoapp.com\".')",
|
||||
"assert($(\"a\").text().match(/cat\\sphotos/gi), 'Your <code>a</code> element should have the anchor text of \"cat photos\"')",
|
||||
"assert($(\"p\") && $(\"p\").length > 2, 'Create a new <code>p</code> element around your <code>a</code> element.')",
|
||||
"assert($(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().is(\"p\"), 'Your <code>a</code> element should be nested within your new <code>p</code> element.')",
|
||||
@ -2603,8 +2602,9 @@
|
||||
" .smaller-image {",
|
||||
" width: 100px;",
|
||||
" }",
|
||||
"",
|
||||
" .gray-background {",
|
||||
" background-color: gray",
|
||||
" background-color: gray;",
|
||||
" }",
|
||||
"</style>",
|
||||
"",
|
||||
@ -2939,9 +2939,9 @@
|
||||
"id": "bad87fee1248bd9aedf08824",
|
||||
"title": "Add Different Margins to Each Side of an Element",
|
||||
"description": [
|
||||
"Give the green box a <code>margin</code> of <code>40px</code> on its top and left side, but only <code>20px</code> on its bottom and right side.",
|
||||
"Sometimes you will want to customize an element so that it has a different <code>margin</code> on each of its sides.",
|
||||
"CSS allows you to control the <code>margin</code> of an element on all four sides with <code>margin-top</code>, <code>margin-right</code>, <code>margin-bottom</code>, and <code>margin-left</code> properties."
|
||||
"CSS allows you to control the <code>margin</code> of an element on all four sides with <code>margin-top</code>, <code>margin-right</code>, <code>margin-bottom</code>, and <code>margin-left</code> properties.",
|
||||
"Give the green box a <code>margin</code> of <code>40px</code> on its top and left side, but only <code>20px</code> on its bottom and right side."
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\".green-box\").css(\"margin-top\") === \"40px\", 'Your <code>green-box</code> class should give the top of elements <code>40px</code> of <code>margin</code>.')",
|
||||
@ -3157,7 +3157,8 @@
|
||||
"<code>}</code>"
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"body\").css(\"background-color\") === \"rgb(0, 0, 0)\", 'Give your <code>body</code> element the <code>background-color</code> of black.')"
|
||||
"assert($(\"body\").css(\"background-color\") === \"rgb(0, 0, 0)\", 'Give your <code>body</code> element the <code>background-color</code> of black.')",
|
||||
"assert(editor.match(/<style>\\s*body\\s*\\{\\s*background-color\\s*:\\s*black;?\\s*\\}\\s*<\\/style>/i), 'Make sure your CSS rule is properly formatted with both and opening and closing curly bracket.')"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"<style>",
|
||||
|
@ -729,7 +729,8 @@
|
||||
"assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n>= 3;}), [3, 4], 'message: <code>drop([1, 2, 3, 4], function(n) {return n >= 3;})</code> should return <code>[3, 4]</code>.');",
|
||||
"assert.deepEqual(drop([1, 2, 3], function(n) {return n > 0; }), [1, 2, 3], 'message: <code>drop([1, 2, 3], function(n) {return n > 0; })</code> should return <code>[1, 2, 3]</code>.');",
|
||||
"assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n > 5;}), [], 'message: <code>drop([1, 2, 3, 4], function(n) {return n > 5;})</code> should return <code>[]</code>.');",
|
||||
"assert.deepEqual(drop([1, 2, 3, 7, 4], function(n) {return n > 3}), [7, 4], 'message: <code>drop([1, 2, 3, 7, 4], function(n) {return n > 3})</code> should return <code>[7, 4]</code>.');"
|
||||
"assert.deepEqual(drop([1, 2, 3, 7, 4], function(n) {return n > 3}), [7, 4], 'message: <code>drop([1, 2, 3, 7, 4], function(n) {return n > 3})</code> should return <code>[7, 4]</code>.');",
|
||||
"assert.deepEqual(drop([1, 2, 3, 9, 2], function(n) {return n > 2}), [3, 9, 2], 'message: <code>drop([1, 2, 3, 9, 2], function(n) {return n > 2})</code> should return <code>[3, 9, 2]</code>.');"
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Arguments object",
|
||||
|
@ -161,7 +161,7 @@
|
||||
"<code>$(\"#target6\").addClass(\"animated fadeOut\")</code>."
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"#target3\").hasClass(\"animated\"), 'Select the <code>button</code>element with the <code>id</code> of <code>target3</code> and use the jQuery <code>addClass()</code> function to give it the class of <code>animated</code>.')",
|
||||
"assert($(\"#target3\").hasClass(\"animated\"), 'Select the <code>button</code> element with the <code>id</code> of <code>target3</code> and use the jQuery <code>addClass()</code> function to give it the class of <code>animated</code>.')",
|
||||
"assert(($(\"#target3\").hasClass(\"fadeOut\") || $(\"#target3\").hasClass(\"fadeout\")) && editor.match(/\\$\\(.#target3.\\)/g), 'Target the element with the id <code>target3</code> and use the jQuery <code>addClass()</code> function to give it the class <code>fadeOut</code>.')",
|
||||
"assert(!editor.match(/class.*animated/g), 'Only use jQuery to add these classes to the element.')"
|
||||
],
|
||||
|
@ -162,7 +162,7 @@
|
||||
"Choose Node.js in the selection area below the name field.",
|
||||
"Click the \"Create workspace\" button.",
|
||||
"Once C9 builds and loads your workspace, you should see a terminal window in the lower right hand corner. In this window use the following commands. You don't need to know what these mean at this point.",
|
||||
"Run this command: <code>git clone http://github.com/reddock/fcc_express && chmod 744 fcc_express/setup.sh && fcc_express/setup.sh && source ~/.profile</code>",
|
||||
"Run this command: <code>git clone https://github.com/FreeCodeCamp/fcc-expressworks.git && chmod 744 fcc-expressworks/setup.sh && fcc-expressworks/setup.sh && source ~/.profile</code>",
|
||||
"Now start this tutorial by running <code>expressworks</code>",
|
||||
"Note that you can resize the c9.io's windows by dragging their borders.",
|
||||
"Make sure that you are always in your project's \"workspace\" directory. You can always navigate back to this directory by running this command: <code>cd ~/workspace</code>.",
|
||||
|
@ -20,9 +20,9 @@
|
||||
"Give your <code>motorBike</code> object a <code>wheels</code>, <code>engines</code> and <code>seats</code> attribute and set them to numbers."
|
||||
],
|
||||
"tests":[
|
||||
"assert(typeof(motorBike.engines) === 'number', 'message: <code>motorBike</code> should have a <code>engines</code> attribute set to a number.');",
|
||||
"assert(typeof(motorBike.wheels) === 'number', 'message: <code>motorBike</code> should have a <code>wheels</code> attribute set to a number.');",
|
||||
"assert(typeof(motorBike.seats) === 'number', 'message: <code>motorBike</code> should have a <code>seats</code> attribute set to a number.');"
|
||||
"assert(typeof motorBike.engines === 'number', 'message: <code>motorBike</code> should have a <code>engines</code> attribute set to a number.');",
|
||||
"assert(typeof motorBike.wheels === 'number', 'message: <code>motorBike</code> should have a <code>wheels</code> attribute set to a number.');",
|
||||
"assert(typeof motorBike.seats === 'number', 'message: <code>motorBike</code> should have a <code>seats</code> attribute set to a number.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var car = {",
|
||||
@ -39,12 +39,15 @@
|
||||
"",
|
||||
" // Only change code above this line.",
|
||||
"",
|
||||
"};",
|
||||
"",
|
||||
"};"
|
||||
],
|
||||
"tail":[
|
||||
"(function() {return JSON.stringify(motorBike);})();"
|
||||
],
|
||||
"solutions":[
|
||||
"var car = {\n \"wheels\":4,\n \"engines\":1,\n \"seats\":5\n};\n\nvar motorBike = {\n \"wheels\": 4,\n \"engines\": 1,\n \"seats\": 2\n};"
|
||||
],
|
||||
"challengeType":1,
|
||||
"type": "waypoint",
|
||||
"type": "waypoint"
|
||||
},
|
||||
{
|
||||
@ -52,19 +55,23 @@
|
||||
"title": "Construct JavaScript Objects with Functions",
|
||||
"description":[
|
||||
"We are also able to create objects using <code>constructor</code> functions.",
|
||||
"Here's an example of a constructor function:",
|
||||
"A <code>constructor</code> function is given a capitalized name to make it clear that it is a <code>constructor</code>.",
|
||||
"Here's an example of a <code>constructor</code> function:",
|
||||
"<code>var Car = function() {</code>",
|
||||
"<code> this.wheels = 4;</code>",
|
||||
"<code> this.engines = 1;</code>",
|
||||
"<code> this.seats = 1;</code>",
|
||||
"<code>};</code>",
|
||||
"Give your <code>myMotorBike</code> object a <code>wheels</code>, <code>engines</code> and <code>seats</code> attribute and set them to numbers.",
|
||||
"You may be confused by the <code>this</code> keyword here. Don't worry, we will get to that very soon."
|
||||
"In a <code>constructor</code> the <code>this</code> variable refers to the new object being created by the constructor. So when we write,",
|
||||
"<code> this.wheels = 4;</code>",
|
||||
"inside of the <code>constructor</code> we are giving the new object it creates a property called <code>wheels</code> with a value of <code>4</code>.",
|
||||
"You can think of a <code>constructor</code> as a description for the object it will create.",
|
||||
"Have your <code>MotorBike</code> <code>constructor</code> describe an object with <code>wheels</code>, <code>engines</code> and <code>seats</code> properties and set them to numbers."
|
||||
],
|
||||
"tests":[
|
||||
"assert(typeof((new MotorBike()).engines) === 'number', 'message: <code>myMotorBike</code> should have a <code>engines</code> attribute set to a number.');",
|
||||
"assert(typeof((new MotorBike()).wheels) === 'number', 'message: <code>myMotorBike</code> should have a <code>wheels</code> attribute set to a number.');",
|
||||
"assert(typeof((new MotorBike()).seats) === 'number', 'message: <code>myMotorBike</code> should have a <code>seats</code> attribute set to a number.');"
|
||||
"assert(typeof (new MotorBike()).engines === 'number', 'message: <code>myMotorBike</code> should have a <code>engines</code> attribute set to a number.');",
|
||||
"assert(typeof (new MotorBike()).wheels === 'number', 'message: <code>myMotorBike</code> should have a <code>wheels</code> attribute set to a number.');",
|
||||
"assert(typeof (new MotorBike()).seats === 'number', 'message: <code>myMotorBike</code> should have a <code>seats</code> attribute set to a number.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var Car = function() {",
|
||||
@ -81,13 +88,107 @@
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"};"
|
||||
],
|
||||
"tail":[
|
||||
"var myMotorBike = new MotorBike();",
|
||||
"(function() {return JSON.stringify(myMotorBike);})();"
|
||||
],
|
||||
"solutions":[
|
||||
"var Car = function() {\n this.wheels = 4;\n this.engines = 1;\n this.seats = 1;\n};\n\nvar myCar = new Car();\n\nvar MotorBike = function() {\n this.engines = 1;\n this.seats = 1;\n this.wheels = 4;\n};\n\nvar myMotorBike = new MotorBike();"
|
||||
],
|
||||
"challengeType":1,
|
||||
"type": "waypoint"
|
||||
},
|
||||
{
|
||||
"id":"cf1111c1c15feddfaeb4bdef",
|
||||
"title":"Make Instances of Objects with a Constructor Function",
|
||||
"description":[
|
||||
"Now let's put that great <code>constructor</code> function we made in the last lesson to use!",
|
||||
"To use a <code>constructor</code> function we call it with the <code>new</code> keyword in front if it like:",
|
||||
"<code>var myCar = new Car();</code>",
|
||||
"<code>myCar</code> is now an <code>instance</code> of the <code>Car</code> constructor that looks like the object it described:",
|
||||
"<code>{</code>",
|
||||
"<code> wheels: 4,</code>",
|
||||
"<code> engines: 1,</code>",
|
||||
"<code> seats: 1</code>",
|
||||
"<code>}</code>",
|
||||
"Note that it is important to use the <code>new</code> keyword when calling a constructor. This is how javascript knows to create a new object and that all the references to <code>this</code> inside the constructor should be referring to this new object.",
|
||||
"Now, once the <code>myCar</code> <code>instance</code> is created it can be used like any other object and can have its properties accessed and modified the same way you would usually. For example:",
|
||||
"<code>myCar.turboType = \"twin\";</code>",
|
||||
"Our <code>myCar</code> variable now has a property <code>turboType</code> with a value of <code>\"twin\"</code>.",
|
||||
"In the editor, use the <code>Car</code> <code>constructor</code> to create a new <code>instance</code> and assign it to <code>myCar</code>.",
|
||||
"Then give <code>myCar</code> a <code>nickname</code> property with a string value."
|
||||
],
|
||||
"tests":[
|
||||
"assert((new Car()).wheels === 4, 'message: The property <code>wheels</code> should still be <code>4</code> in the object <code>constructor</code>.');",
|
||||
"assert(typeof (new Car()).nickname === 'undefined', 'message: There should not be a property <code>nickname</code> in the object <code>constructor</code>.');",
|
||||
"assert(myCar.wheels === 4, 'message: The property <code>wheels</code> of <code>myCar</code> should equal <code>4</code>.');",
|
||||
"assert(typeof myCar.nickname === 'string', 'message: The property <code>nickname</code> of <code>myCar</code> should be a string.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var Car = function() {",
|
||||
" this.wheels = 4;",
|
||||
" this.engines = 1;",
|
||||
" this.seats = 1;",
|
||||
"};",
|
||||
"",
|
||||
"var myMotorBike = new MotorBike();",
|
||||
"// Only change code below this line.",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"var myCar;"
|
||||
],
|
||||
"tail":[
|
||||
"(function() {return JSON.stringify(myCar);})();"
|
||||
],
|
||||
"solutions":[
|
||||
"var Car = function() {\n this.wheels = 4;\n this.engines = 1;\n this.seats = 1;\n};\n\nvar myCar = new Car();\n\nmyCar.nickname = \"Lucy\";"
|
||||
],
|
||||
"challengeType":1,
|
||||
"type": "waypoint"
|
||||
},
|
||||
{
|
||||
"id":"563cfb55594311ffcb333c70",
|
||||
"title":"Make Unique Objects by Passing Parameters to our Constructor",
|
||||
"description":[
|
||||
"The <code>constructor</code> we have is great, but what if we don't always want to create the same object?",
|
||||
"To solve this we can add <code>parameters</code> to our <code>constructor</code>. We do this like the following example:",
|
||||
"<code>var Car = function(wheels, seats, engines) {</code>",
|
||||
"<code> this.wheels = wheels;</code>",
|
||||
"<code> this.seats = seats;</code>",
|
||||
"<code> this.engines = engines;</code>",
|
||||
"<code>};</code>",
|
||||
"Now we can pass in <code>arguments</code> when we call our <code>constructor</code>.",
|
||||
"<code>var myCar = new Car(6, 3, 1);</code>",
|
||||
"This code will create an object that uses the <code>arguments</code> we passed in and looks like:",
|
||||
"<code>{</code>",
|
||||
"<code> wheels: 6,</code>",
|
||||
"<code> seats: 3,</code>",
|
||||
"<code> engines: 1</code>",
|
||||
"<code>}</code>",
|
||||
"Now give it a try yourself! Alter the <code>Car</code> <code>constructor</code> to use <code>parameters</code> to assign values to the <code>wheels</code>, <code>seats</code>, and <code>engines</code> properties.",
|
||||
"Then call your new <code>constructor</code> with three number <code>arguments</code> and assign it to <code>myCar</code> to see it in action."
|
||||
],
|
||||
"tests":[
|
||||
"assert((function(){var testCar = new Car(3,1,2); return testCar.wheels === 3 && testCar.seats === 1 && testCar.engines === 2;})(), 'message: Calling <code>new Car(3,1,2)</code> should produce an object with a <code>wheels</code> property of <code>3</code>, a <code>seats</code> property of <code>1</code>, and an <code>engines</code> property of <code>2</code>.');",
|
||||
"assert(typeof myCar.wheels === 'number' && typeof myCar.seats === 'number' && typeof myCar.engines === 'number', 'message: <code>myCar</code> should have number values for the <code>wheels</code>, <code>seats</code>, and <code>engines</code> properties.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var Car = function() {",
|
||||
" //Change this constructor",
|
||||
" this.wheels = 4;",
|
||||
" this.seats = 1;",
|
||||
" this.engines = 1;",
|
||||
"};",
|
||||
"",
|
||||
"(function() {return JSON.stringify(myMotorBike);})();"
|
||||
"//Try it out here",
|
||||
"var myCar;",
|
||||
"",
|
||||
"// Only change code above this line",
|
||||
"",
|
||||
"(function() {return JSON.stringify(myCar);})();"
|
||||
],
|
||||
"solutions":[
|
||||
"var Car = function(wheels,seats,engines) {\n this.wheels = wheels;\n this.seats = seats;\n this.engines = engines;\n};\n\nvar myCar = new Car(4,1,1);"
|
||||
],
|
||||
"challengeType":1,
|
||||
"type": "waypoint"
|
||||
@ -97,89 +198,56 @@
|
||||
"title":"Make Object Properties Private",
|
||||
"description":[
|
||||
"Objects have their own attributes, called <code>properties</code>, and their own functions, called <code>methods</code>.",
|
||||
"In the previous challenge, we used the <code>this</code> keyword to reference <code>public properties</code> and <code>public methods</code> of the current object.",
|
||||
"In the previous challenges, we used the <code>this</code> keyword to reference <code>public properties</code> of the current object.",
|
||||
"We can also create <code>private properties</code> and <code>private methods</code>, which aren't accessible from outside the object.",
|
||||
"To do this, just declare properties or functions within the constructor.",
|
||||
"Let's create an object with two functions. One attached as a property and one not.",
|
||||
"See if you can keep <code>myBike.speed</code> and <code>myBike.addUnit</code> private, while making <code>myBike.getSpeed</code> publicly accessible."
|
||||
"To do this, we create the variable inside the <code>constructor</code> using the <code>var</code> keyword we're familiar with, instead of creating it as a <code>property</code> of <code>this</code>.",
|
||||
"This is useful for when we need to store information about an object but we want to control how it is used by outside code.",
|
||||
"For example, what if we want to store the <code>speed</code> our car is traveling at but we only want outside code to be able to modify it by accelerating or decelerating, so the speed changes in a controlled way?",
|
||||
"In the editor you can see an example of a <code>Car</code> <code>constructor</code> that implements this pattern.",
|
||||
"Now try it yourself! Modify the <code>Bike</code> <code>constructor</code> to have a <code>private property</code> called <code>gear</code> and two <code>public methods</code> called <code>getGear</code> and <code>setGear</code> to get and set that value."
|
||||
],
|
||||
"tests":[
|
||||
"assert(typeof(myBike.getSpeed)!=='undefined' && typeof(myBike.getSpeed) === 'function', 'message: The method getSpeed of myBike should be accessible outside the object.');",
|
||||
"assert(typeof(myBike.speed) === 'undefined', 'message: <code>myBike.speed</code> should be undefined.');",
|
||||
"assert(typeof(myBike.addUnit) === 'undefined', 'message: <code>myBike.addUnit</code> should remain undefined.');"
|
||||
"assert(typeof myBike.getGear !== 'undefined' && typeof(myBike.getGear) === 'function', 'message: The method <code>getGear</code> of <code>myBike</code> should be accessible outside the object.');",
|
||||
"assert(typeof myBike.setGear !== 'undefined' && typeof(myBike.setGear) === 'function', 'message: The method <code>setGear</code> of <code>myBike</code> should be accessible outside the object.');",
|
||||
"assert(typeof myBike.gear === 'undefined', 'message: <code>myBike.gear</code> should remain undefined.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var Car = function() {",
|
||||
" // this is a private variable",
|
||||
" var gear = 1;",
|
||||
" // this is a private function (also known as a private method)",
|
||||
" function addStyle(styleMe){",
|
||||
" return 'The Current Gear Is: ' + styleMe;",
|
||||
" }",
|
||||
" // this is a public method",
|
||||
" this.getGear = function() {",
|
||||
" return addStyle(this.gear);",
|
||||
" // this is a private variable",
|
||||
" var speed = 10;",
|
||||
"",
|
||||
" // these are public methods",
|
||||
" this.accelerate = function(change) {",
|
||||
" speed += change;",
|
||||
" };",
|
||||
"",
|
||||
" this.decelerate = function() {",
|
||||
" speed -= 5;",
|
||||
" };",
|
||||
"",
|
||||
" this.getSpeed = function() {",
|
||||
" return speed;",
|
||||
" };",
|
||||
"};",
|
||||
"",
|
||||
"var Bike = function() {",
|
||||
"",
|
||||
" // Only change code below this line.",
|
||||
"",
|
||||
" this.speed = 100;",
|
||||
"",
|
||||
" function addUnit(value) {",
|
||||
" return value + \"KM/H\";",
|
||||
" }",
|
||||
"",
|
||||
" getSpeed = function () {",
|
||||
" return addUnit(speed);",
|
||||
" };",
|
||||
"",
|
||||
" // Only change code above this line.",
|
||||
"};",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
"var myCar = new Car();",
|
||||
"",
|
||||
"var myBike = new Bike();",
|
||||
"",
|
||||
"if(myBike.hasOwnProperty('getSpeed')){(function() {return JSON.stringify(myBike.getSpeed());})();}"
|
||||
"var myBike = new Bike();"
|
||||
],
|
||||
"challengeType":1,
|
||||
"type": "waypoint"
|
||||
},
|
||||
{
|
||||
"id":"cf1111c1c15feddfaeb4bdef",
|
||||
"title":"Make Instances of Objects with a Constructor Function",
|
||||
"description":[
|
||||
"Sometimes you'll want to be able to easily create many copies of an objects that all share the same methods.",
|
||||
"Objects have their own attributes, called <code>properties</code>, and their own functions, called <code>methods</code>.",
|
||||
"You can create <code>instances</code> of an object using a <code>constructor</code>.",
|
||||
"A constructor is a function that creates instances of an object that share the same methods and properties",
|
||||
"Each new <code>instance</code> of this object <code>inherits</code> all the <code>properties</code> and <code>methods</code> of your original object.",
|
||||
"Once an <code>instance</code> has been created you can add <code>properties</code> to that <code>instance</code> individually.",
|
||||
"Add an <code>engines</code> property with a number value to the <code>myCar</code> instance."
|
||||
"tail":[
|
||||
"if(myBike.hasOwnProperty('getGear')){(function() {return JSON.stringify(myBike.getGear());})();}"
|
||||
],
|
||||
"tests":[
|
||||
"assert((new Car()).wheels === 4, 'message: The property <code>wheels</code> should still be 4 in the object constructor.');",
|
||||
"assert(typeof((new Car()).engines) === 'undefined', 'message: There should not be a property <code>engines</code> in the object constructor.');",
|
||||
"assert(myCar.wheels === 4, 'message: The property <code>wheels</code> of myCar should equal 4.');",
|
||||
"assert(typeof(myCar.engines) === 'number', 'message: The property <code>engines</code> of myCar should be a number.');"
|
||||
],
|
||||
"challengeSeed":[
|
||||
"var Car = function() {",
|
||||
" this.wheels = 4;",
|
||||
"};",
|
||||
"",
|
||||
"// Only change code below this line.",
|
||||
"var myCar = new Car();",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"(function() {return JSON.stringify(myCar);})();"
|
||||
"solutions":[
|
||||
"var Car = function() {\n var speed = 10;\n\n this.accelerate = function(change) {\n speed += change;\n };\n\n this.decelerate = function() {\n speed -= 5;\n };\n\n this.getSpeed = function() {\n return speed;\n };\n};\n\nvar Bike = function() {\n var gear = 1;\n \n this.getGear = function() {\n return gear;\n };\n \n this.setGear = function(newGear) {\n gear = newGear;\n };\n};\n\nvar myCar = new Car();\n\nvar myBike = new Bike();"
|
||||
],
|
||||
"challengeType":1,
|
||||
"type": "waypoint"
|
||||
@ -207,11 +275,8 @@
|
||||
"",
|
||||
"// Only change code below this line.",
|
||||
"",
|
||||
"",
|
||||
"var newArray = oldArray;",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
"(function() {return newArray;})();"
|
||||
@ -225,7 +290,7 @@
|
||||
"description":[
|
||||
"The array method <code>reduce</code> is used to iterate through an array and condense it into one value.",
|
||||
"To use <code>reduce</code> you pass in a callback whose arguments are an accumulator (in this case, <code>previousVal</code>) and the current value (<code>currentVal</code>).",
|
||||
"<code>reduce</code> 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.",
|
||||
"<code>reduce</code> 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 <code>currentVal</code> will start with the second array element.",
|
||||
"Here is an example of <code>reduce</code> being used to subtract all the values of an array:",
|
||||
"<code>var singleVal = array.reduce(function(previousVal, currentVal) {</code>",
|
||||
"<code> return previousVal - currentVal;</code>",
|
||||
@ -239,13 +304,10 @@
|
||||
"challengeSeed":[
|
||||
"var array = [4,5,6,7,8];",
|
||||
"",
|
||||
"",
|
||||
"// Only change code below this line.",
|
||||
"",
|
||||
"var singleVal = array;",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
"(function() {return singleVal;})();"
|
||||
@ -325,10 +387,10 @@
|
||||
"description": [
|
||||
"You can use the <code>reverse</code> method to reverse the elements of an array.",
|
||||
"<code>reverse</code> is another array method that alters the array in place, but it also returns the reversed array.",
|
||||
"Add a line of code that uses <code>reverse</code> to reverse the <code>array</code> variable."
|
||||
"Use <code>reverse</code> to reverse the <code>array</code> variable and assign it to <code>myArray</code>."
|
||||
],
|
||||
"tests": [
|
||||
"assert.deepEqual(array, [7,6,5,4,3,2,1], 'message: You should reverse the array.');",
|
||||
"assert.deepEqual(newArray, [7,6,5,4,3,2,1], 'message: You should reverse the array.');",
|
||||
"assert(editor.getValue().match(/\\.reverse\\s*\\(\\)/gi), 'message: You should use the <code>reverse</code> method.');",
|
||||
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7/gi), 'message: You should only be using <code>reverse</code> to modify <code>array</code>.');"
|
||||
],
|
||||
@ -337,11 +399,11 @@
|
||||
"",
|
||||
"// Only change code below this line.",
|
||||
"",
|
||||
"",
|
||||
"var newArray = array;",
|
||||
"",
|
||||
"// Only change code above this line.",
|
||||
"",
|
||||
"(function() {return array;})();"
|
||||
"(function() {return newArray;})();"
|
||||
],
|
||||
"challengeType": 1,
|
||||
"type": "waypoint"
|
||||
@ -410,7 +472,7 @@
|
||||
"title":"Join Strings with .join",
|
||||
"description":[
|
||||
"We can use the <code>join</code> 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 <code>join</code> 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 <code>join</code> to join all of the elements of an array into a string with all the elements separated by word `Na`:",
|
||||
"<code>var joinMe = [\"Na \", \"Na \", \"Na \", \"Na \", \"Batman!\"];</code>",
|
||||
"<code>var joinedString = joinMe.join(\"Na \");</code>",
|
||||
"<code>console.log(joinedString);</code>",
|
||||
|
@ -117,8 +117,8 @@
|
||||
],
|
||||
"tests": [
|
||||
"assert.deepEqual(pairwise([1, 4, 2, 3, 0, 5], 7), 11, 'message: <code>pairwise([1, 4, 2, 3, 0, 5], 7)</code> should return 11.');",
|
||||
"assert.deepEqual(pairwise([1, 3, 2, 4], 4), 1, 'message: <code>pairwise([1, 3, 2, 4], 4), 1</code> should return 1.');",
|
||||
"assert.deepEqual(pairwise([1,1,1], 2), 1, 'message: <code>pairwise([1,1,1], 2)</code> should return 1.');",
|
||||
"assert.deepEqual(pairwise([1, 3, 2, 4], 4), 1, 'message: <code>pairwise([1, 3, 2, 4], 4)</code> should return 1.');",
|
||||
"assert.deepEqual(pairwise([1, 1, 1], 2), 1, 'message: <code>pairwise([1, 1, 1], 2)</code> should return 1.');",
|
||||
"assert.deepEqual(pairwise([0, 0, 0, 0, 1, 1], 1), 10, 'message: <code>pairwise([0, 0, 0, 0, 1, 1], 1)</code> should return 10.');",
|
||||
"assert.deepEqual(pairwise([], 100), 0, 'message: <code>pairwise([], 100)</code> should return 0.');"
|
||||
],
|
||||
|
@ -10,7 +10,10 @@ module.exports = function getChallenges() {
|
||||
try {
|
||||
return getFilesFor('challenges')
|
||||
.map(function(file) {
|
||||
return require('./challenges/' + file);
|
||||
var challengeSpec = require('./challenges/' + file);
|
||||
challengeSpec.fileName = file;
|
||||
|
||||
return challengeSpec;
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('error', e);
|
||||
|
@ -18,6 +18,7 @@ destroy()
|
||||
var order = challengeSpec.order;
|
||||
var block = challengeSpec.name;
|
||||
var isBeta = !!challengeSpec.isBeta;
|
||||
var fileName = challengeSpec.fileName;
|
||||
console.log('parsed %s successfully', block);
|
||||
|
||||
// challenge file has no challenges...
|
||||
@ -37,6 +38,8 @@ destroy()
|
||||
.toLowerCase()
|
||||
.replace(/\:/g, '')
|
||||
.replace(/\s/g, '-');
|
||||
|
||||
challenge.fileName = fileName;
|
||||
challenge.order = order;
|
||||
challenge.suborder = index + 1;
|
||||
challenge.block = block;
|
||||
|
@ -4,7 +4,15 @@ import moment from 'moment';
|
||||
import { Observable, Scheduler } from 'rx';
|
||||
import assign from 'object.assign';
|
||||
import debugFactory from 'debug';
|
||||
import utils from '../utils';
|
||||
|
||||
import {
|
||||
dasherize,
|
||||
unDasherize,
|
||||
getMDNLinks,
|
||||
randomVerb,
|
||||
randomPhrase,
|
||||
randomCompliment
|
||||
} from '../utils';
|
||||
|
||||
import {
|
||||
saveUser,
|
||||
@ -16,6 +24,8 @@ import {
|
||||
ifNoUserSend
|
||||
} from '../utils/middleware';
|
||||
|
||||
import getFromDisk$ from '../utils/getFromDisk$';
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
const isBeta = !!process.env.BETA;
|
||||
const debug = debugFactory('freecc:challenges');
|
||||
@ -31,10 +41,6 @@ const challengeView = {
|
||||
7: 'coursewares/showStep'
|
||||
};
|
||||
|
||||
const dasherize = utils.dasherize;
|
||||
const unDasherize = utils.unDasherize;
|
||||
const getMDNLinks = utils.getMDNLinks;
|
||||
|
||||
/*
|
||||
function makeChallengesUnique(challengeArr) {
|
||||
// clone and reverse challenges
|
||||
@ -262,6 +268,12 @@ module.exports = function(app) {
|
||||
return testChallengeName.test(challenge.name);
|
||||
})
|
||||
.last({ defaultValue: null })
|
||||
.flatMap(challenge => {
|
||||
if (challenge && isDev) {
|
||||
return getFromDisk$(challenge);
|
||||
}
|
||||
return Observable.just(challenge);
|
||||
})
|
||||
.flatMap(challenge => {
|
||||
|
||||
// Handle not found
|
||||
@ -288,27 +300,32 @@ module.exports = function(app) {
|
||||
|
||||
// save user does nothing if user does not exist
|
||||
return Observable.just({
|
||||
|
||||
title: challenge.name,
|
||||
dashedName: origChallengeName,
|
||||
name: challenge.name,
|
||||
details: challenge.description,
|
||||
description: challenge.description,
|
||||
tests: challenge.tests,
|
||||
challengeSeed: challenge.challengeSeed,
|
||||
verb: utils.randomVerb(),
|
||||
phrase: utils.randomPhrase(),
|
||||
compliment: utils.randomCompliment(),
|
||||
challengeId: challenge.id,
|
||||
challengeType: challenge.challengeType,
|
||||
dashedName: origChallengeName,
|
||||
|
||||
challengeSeed: challenge.challengeSeed,
|
||||
head: challenge.head,
|
||||
tail: challenge.tail,
|
||||
tests: challenge.tests,
|
||||
|
||||
// video challenges
|
||||
video: challenge.challengeSeed[0],
|
||||
|
||||
// bonfires specific
|
||||
difficulty: Math.floor(+challenge.difficulty),
|
||||
bonfires: challenge,
|
||||
MDNkeys: challenge.MDNlinks,
|
||||
MDNlinks: getMDNLinks(challenge.MDNlinks),
|
||||
|
||||
// htmls specific
|
||||
environment: utils.whichEnvironment()
|
||||
verb: randomVerb(),
|
||||
phrase: randomPhrase(),
|
||||
compliment: randomCompliment()
|
||||
});
|
||||
})
|
||||
.subscribe(
|
||||
|
@ -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);
|
||||
});
|
||||
};
|
||||
|
@ -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,
|
||||
@ -65,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(
|
||||
@ -206,45 +204,75 @@ module.exports = function(app) {
|
||||
);
|
||||
}
|
||||
|
||||
function getStories(req, res, next) {
|
||||
MongoClient.connect(secrets.db, function(err, database) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
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,
|
||||
textScore: {
|
||||
$meta: 'textScore'
|
||||
}
|
||||
}, {
|
||||
sort: {
|
||||
textScore: {
|
||||
$meta: 'textScore'
|
||||
}
|
||||
}
|
||||
}).toArray(function(err, items) {
|
||||
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 !== null && items.length !== 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
const query = {
|
||||
'$text': {
|
||||
// protect against NoSQL injection
|
||||
'$search': search.replace('$', '')
|
||||
}
|
||||
};
|
||||
|
||||
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'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return app.dataSources.db.connector
|
||||
.collection('story')
|
||||
.find(query, fields, options)
|
||||
.toArray(function(err, items) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (items && items.length !== 0) {
|
||||
return res.json(items);
|
||||
}
|
||||
return res.sendStatus(404);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function upvote(req, res, next) {
|
||||
|
@ -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() {
|
||||
|
@ -4,7 +4,7 @@
|
||||
"quote": "By building a robust and highly functional web app I was able to not only increase my confidence but was able to show potential employers what I was able to create. Both were huge for me and led me to getting a fantastic job.",
|
||||
"github": "MetaCoderHirschl",
|
||||
"linkedin": "https://www.linkedin.com/profile/view?id=ADEAAAKX2fEBfeZ1GVdOh-c0zzkYZKw38o8qzow",
|
||||
"image": "http://i.imgur.com/58XvKfe.jpg"
|
||||
"image": "http://i.imgur.com/nsvNixW.jpg"
|
||||
},
|
||||
{
|
||||
"camper": "Branden Byers",
|
||||
@ -57,7 +57,7 @@
|
||||
},
|
||||
{
|
||||
"camper": "Brian Grant",
|
||||
"quote": "I've received new employment opportunities and I have not even finished Free Code Camp's first 800 hours of training yet.",
|
||||
"quote": "Free Code Camp's a great way for disabled veterans like me to retrain. I'm receiving engineering job offers, and I haven't even finished yet.",
|
||||
"github": "codeseekingman",
|
||||
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAEUqXoBFOq1SWQrBsTMHG4ij9Ss4Qqnrtg",
|
||||
"image": "http://i.imgur.com/QPpjPac.jpg"
|
||||
|
37
server/utils/getFromDisk$.js
Normal file
37
server/utils/getFromDisk$.js
Normal file
@ -0,0 +1,37 @@
|
||||
import _ from 'lodash';
|
||||
import path from 'path';
|
||||
import { Observable } from 'rx';
|
||||
|
||||
const basePath = process.cwd() + '/seed/challenges/';
|
||||
|
||||
export default function getFromDisk$(challenge) {
|
||||
if (challenge && !challenge.fileName) {
|
||||
throw new Error(
|
||||
`Challenge ${challenge.name} has no fileName.
|
||||
Did you remember run node seed?`
|
||||
);
|
||||
}
|
||||
delete require.cache[require.resolve(
|
||||
path.join(basePath, challenge.fileName)
|
||||
)];
|
||||
|
||||
return Observable.just(require(path.join(basePath, challenge.fileName)))
|
||||
.map(challengeSpec => challengeSpec.challenges[challenge.suborder - 1])
|
||||
.map(challenge => {
|
||||
challenge.head = challenge.head || [];
|
||||
challenge.tail = challenge.tail || [];
|
||||
challenge.challengeType = '' + challenge.challengeType;
|
||||
|
||||
challenge.name =
|
||||
_.capitalize(challenge.type) +
|
||||
': ' +
|
||||
challenge.title.replace(/[^a-zA-Z0-9\s]/g, '');
|
||||
|
||||
challenge.dashedName = challenge.name
|
||||
.toLowerCase()
|
||||
.replace(/\:/g, '')
|
||||
.replace(/\s/g, '-');
|
||||
|
||||
return challenge;
|
||||
});
|
||||
}
|
@ -80,14 +80,26 @@ block content
|
||||
#cal-heatmap.d3-centered
|
||||
script.
|
||||
$(document).ready(function () {
|
||||
var estUTCOffset = -5;
|
||||
// moment returns the utc offset in minutes
|
||||
var userUTCOffset = moment().utcOffset() / 60;
|
||||
var secondsToOffset =
|
||||
(estUTCOffset - userUTCOffset) * 3600;
|
||||
var cal = new CalHeatMap();
|
||||
var calendar = !{JSON.stringify(calender)};
|
||||
var offsetCalendar = {};
|
||||
for (var prop in calendar) {
|
||||
if (calendar.hasOwnProperty(prop)) {
|
||||
var offsetProp = prop + secondsToOffset;
|
||||
offsetCalendar[offsetProp] = calendar[prop];
|
||||
}
|
||||
}
|
||||
cal.init({
|
||||
itemSelector: "#cal-heatmap",
|
||||
domain: "month",
|
||||
subDomain: "x_day",
|
||||
domainGutter: 10,
|
||||
data: calendar,
|
||||
data: offsetCalendar,
|
||||
cellSize: 15,
|
||||
align: 'center',
|
||||
cellRadius: 3,
|
||||
|
@ -70,16 +70,6 @@ block content
|
||||
br
|
||||
#testSuite.negative-10
|
||||
br
|
||||
script(type="text/javascript").
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var started = Math.floor(Date.now());
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var dashedName = !{JSON.stringify(dashedName)};
|
||||
var _ = R;
|
||||
var dashed = !{JSON.stringify(dashedName)};
|
||||
|
||||
.col-md-8.col-lg-9
|
||||
.editorScrollDiv(style = "overflow-y: auto; overflow-x: hidden;")
|
||||
@ -87,7 +77,7 @@ block content
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeEditor(autofocus=true, style='display: none;')
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
|
||||
|
||||
#complete-courseware-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeIn.fast-animation
|
||||
@ -103,12 +93,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#next-challenge.btn.btn-lg.btn-primary.btn-block(href="/challenges/next-challenge?id="+challengeId) 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
|
||||
@ -119,15 +111,30 @@ block content
|
||||
a.btn.btn-lg.btn-info.btn-block#reset-button(href='#', data-dismiss='modal', aria-hidden='true') Clear my code
|
||||
a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Cancel
|
||||
include ../partials/challenge-modals
|
||||
script.
|
||||
script(type="text/javascript").
|
||||
var common = window.common = { init: [] };
|
||||
|
||||
common.tests = !{JSON.stringify(tests)};
|
||||
common.head = !{JSON.stringify(head)};
|
||||
common.tail = !{JSON.stringify(tail)};
|
||||
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
common.challengeType = !{JSON.stringify(challengeType)};
|
||||
common.dashedName = !{JSON.stringify(dashedName)};
|
||||
|
||||
common.started = Math.floor(Date.now());
|
||||
common.username = !{JSON.stringify(user && user.username || '')};
|
||||
|
||||
include ../partials/challenge-footer
|
||||
script.
|
||||
document.addEventListener('gitter-sidecar-ready', function(e) {
|
||||
if (window.main) {
|
||||
window.main.chat.createHelpChat('freecodecamp/helpbonfires', '#challenge-help-btn', 'Bonfires Help');
|
||||
}
|
||||
});
|
||||
|
||||
var MDNlinks = !{JSON.stringify(MDNlinks)};
|
||||
if (!MDNlinks.length) {
|
||||
if (!!{JSON.stringify(MDNlinks.length)}) {
|
||||
$('#MDN-links').addClass('collapse');
|
||||
}
|
||||
|
@ -58,26 +58,12 @@ block content
|
||||
.button-spacer
|
||||
#testSuite
|
||||
br
|
||||
script(type="text/javascript").
|
||||
$('#next-courseware-button').attr('disabled', 'disabled');
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var prodOrDev = !{JSON.stringify(environment)};
|
||||
var dashedName = !{JSON.stringify(dashedName)};
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var started = Math.floor(Date.now());
|
||||
.col-md-5.col-lg-6
|
||||
.editorScrollDiv(style = "overflow-y: auto; overflow-x: hidden;")
|
||||
#mainEditorPanel
|
||||
form.code
|
||||
.codeMirrorView
|
||||
textarea#codeEditor(autofocus=true, style='display: none;')
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
script.
|
||||
editor.setOption('lint', false);
|
||||
editor.setOption("mode", "text/html");
|
||||
.col-md-4.col-lg-3
|
||||
.hidden-xs.hidden-sm
|
||||
img.iphone-position.iframe-scroll(src="https://s3.amazonaws.com/freecodecamp/iphone6-frame.png", style = "z-index: -2;")
|
||||
@ -98,11 +84,31 @@ block content
|
||||
if(user)
|
||||
#submit-challenge.animated.fadeIn.btn.btn-lg.btn-primary.btn-block Submit and go to my next challenge (ctrl + enter)
|
||||
else
|
||||
#next-challenge.btn.btn-lg.btn-primary.btn-block Go to my next challenge (ctrl + enter)
|
||||
a#next-challenge.btn.btn-lg.btn-primary.btn-block(href="/challenges/next-challenge?id="+challengeId) Go to my next challenge (ctrl + enter)
|
||||
include ../partials/challenge-modals
|
||||
script(type="text/javascript").
|
||||
$('#next-courseware-button').attr('disabled', 'disabled');
|
||||
var common = window.common || { init: [] };
|
||||
|
||||
common.tests = !{JSON.stringify(tests)};
|
||||
common.head = !{JSON.stringify(head)};
|
||||
common.tail = !{JSON.stringify(tail)};
|
||||
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
common.challengeType = !{JSON.stringify(challengeType)};
|
||||
common.dashedName = !{JSON.stringify(dashedName)};
|
||||
|
||||
common.started = Math.floor(Date.now());
|
||||
|
||||
include ../partials/challenge-footer
|
||||
script.
|
||||
document.addEventListener('gitter-sidecar-ready', function(e) {
|
||||
if (window.main) {
|
||||
window.main.chat.createHelpChat('freecodecamp/help', '#challenge-help-btn');
|
||||
}
|
||||
});
|
||||
|
||||
editor.setOption('lint', false);
|
||||
editor.setOption("mode", "text/html");
|
||||
|
@ -61,25 +61,12 @@ block content
|
||||
br
|
||||
#testSuite.negative-10
|
||||
br
|
||||
script(type="text/javascript").
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var dashedName = !{JSON.stringify(dashedName)};
|
||||
var started = Math.floor(Date.now());
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var _ = R;
|
||||
var dashed = !{JSON.stringify(dashedName)};
|
||||
.col-md-8.col-lg-9
|
||||
.editorScrollDiv(style = "overflow-y: auto; overflow-x: hidden;")
|
||||
#mainEditorPanel
|
||||
form.code
|
||||
.codeMirrorView
|
||||
textarea#codeEditor(autofocus=true, style='display: none;')
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
script.
|
||||
editor.setOption("mode", "javascript");
|
||||
#complete-courseware-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeIn.fast-animation
|
||||
.modal-content
|
||||
@ -95,11 +82,26 @@ block content
|
||||
if (user)
|
||||
#submit-challenge.animated.fadeIn.btn.btn-lg.btn-primary.btn-block Submit and go to my next challenge (ctrl + enter)
|
||||
else
|
||||
#next-challenge.animated.fadeIn.btn.btn-lg.btn-primary.btn-block Go to my next challenge (ctrl + enter)
|
||||
a#next-challenge.animated.fadeIn.btn.btn-lg.btn-primary.btn-block(href="/challenges/next-challenge?id="+challengeId) Go to my next challenge (ctrl + enter)
|
||||
include ../partials/challenge-modals
|
||||
script(type="text/javascript").
|
||||
var common = window.common = { init: [] };
|
||||
|
||||
common.tests = !{JSON.stringify(tests)};
|
||||
common.head = !{JSON.stringify(head)};
|
||||
common.tail = !{JSON.stringify(tail)};
|
||||
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
common.challengeType = !{JSON.stringify(challengeType)};
|
||||
common.dashedName = !{JSON.stringify(dashedName)};
|
||||
|
||||
common.started = Math.floor(Date.now());
|
||||
|
||||
include ../partials/challenge-footer
|
||||
script.
|
||||
var MDNlinks = !{JSON.stringify(MDNlinks)};
|
||||
if (!MDNlinks.length) {
|
||||
if (!!{JSON.stringify(MDNlinks.length)}) {
|
||||
$('#MDN-links').addClass('collapse');
|
||||
}
|
||||
document.addEventListener('gitter-sidecar-ready', function(e) {
|
||||
@ -107,3 +109,4 @@ block content
|
||||
window.main.chat.createHelpChat('freecodecamp/help', '#challenge-help-btn');
|
||||
}
|
||||
});
|
||||
editor.setOption("mode", "javascript");
|
||||
|
@ -34,14 +34,15 @@ block content
|
||||
#challenge-step-btn-submit.animated.fadeIn.btn.btn-lg.btn-primary.btn-block Submit and go to my next challenge
|
||||
else
|
||||
a.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) Go to my next challenge
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
script.
|
||||
var common = window.common || { init: [] };
|
||||
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.challengeType = 7;
|
||||
common.challengeType = !{JSON.stringify(challengeType)};
|
||||
common.dashedName = !{JSON.stringify(dashedName || '')};
|
||||
common.isHonest = !{JSON.stringify(isHonest || false)};
|
||||
common.isFrontEndCert = !{JSON.stringify(isFrontEndCert || false)};
|
||||
common.isFullStackCert = !{JSON.stringify(isFullStackCert || false)};
|
||||
common.challengeSeed = !{JSON.stringify(challengeSeed || [])};
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
|
@ -75,14 +75,19 @@ block content
|
||||
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) I've completed this challenge (ctrl + enter)
|
||||
script.
|
||||
$('body').bind('keydown', controlEnterHandler);
|
||||
|
||||
include ../partials/challenge-modals
|
||||
script.
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var dashedName = !{JSON.stringify(dashedName)};
|
||||
var common = window.common = { init: [] };
|
||||
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.challengeType = !{JSON.stringify(challengeType)};
|
||||
common.dashedName = !{JSON.stringify(dashedName)};
|
||||
|
||||
document.addEventListener('gitter-sidecar-ready', function(e) {
|
||||
if (window.main) {
|
||||
window.main.chat.createHelpChat('freecodecamp/help', '#challenge-help-btn');
|
||||
}
|
||||
});
|
||||
include ../partials/challenge-modals
|
||||
include ../partials/challenge-footer
|
||||
|
@ -37,29 +37,6 @@ block content
|
||||
var userLoggedIn = false;
|
||||
br
|
||||
script(type="text/javascript").
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var started = Math.floor(Date.now());
|
||||
var dashedName = !{JSON.stringify(dashedName)};
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var controlEnterHandler = function (e) {
|
||||
$('body').unbind('keydown');
|
||||
if (e.metaKey && e.keyCode === 13 ||
|
||||
e.ctrlKey && e.keyCode === 13) {
|
||||
$('#complete-zipline-or-basejump-dialog').modal('show');
|
||||
} else {
|
||||
$('body').bind('keydown', controlEnterHandler);
|
||||
}
|
||||
};
|
||||
var modalControlEnterHandler = function (e) {
|
||||
$('#complete-zipline-or-basejump-dialog').unbind('keydown');
|
||||
if (e.metaKey && e.keyCode === 13 ||
|
||||
e.ctrlKey && e.keyCode === 13) {
|
||||
$('#next-courseware-button').click();
|
||||
} else {
|
||||
$('#complete-zipline-or-basejump-dialog').on('keydown', modalControlEnterHandler);
|
||||
}
|
||||
};
|
||||
|
||||
#complete-zipline-or-basejump-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeIn.fast-animation
|
||||
@ -92,24 +69,57 @@ block content
|
||||
a.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid') Go to my next challenge
|
||||
.button-spacer
|
||||
script.
|
||||
$('#complete-zipline-or-basejump-dialog').on('keydown', modalControlEnterHandler);
|
||||
else
|
||||
a.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) Go to my next challenge
|
||||
script.
|
||||
$('body').on('keydown', controlEnterHandler);
|
||||
include ../partials/challenge-modals
|
||||
script.
|
||||
var common = window.common || { init: [] };
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.started = Math.floor(Date.now());
|
||||
common.dashedName = !{JSON.stringify(dashedName)};
|
||||
common.challengeType = !{JSON.stringify(challengeType)};
|
||||
|
||||
common.controlEnterHandler = function (e) {
|
||||
$('body').unbind('keydown');
|
||||
if (e.metaKey && e.keyCode === 13 ||
|
||||
e.ctrlKey && e.keyCode === 13) {
|
||||
$('#complete-zipline-or-basejump-dialog').modal('show');
|
||||
} else {
|
||||
$('body').bind('keydown', common.controlEnterHandler);
|
||||
}
|
||||
};
|
||||
|
||||
common.modalControlEnterHandler = function (e) {
|
||||
$('#complete-zipline-or-basejump-dialog').unbind('keydown');
|
||||
if (e.metaKey && e.keyCode === 13 ||
|
||||
e.ctrlKey && e.keyCode === 13) {
|
||||
$('#next-courseware-button').click();
|
||||
} else {
|
||||
$('#complete-zipline-or-basejump-dialog').on('keydown', common.modalControlEnterHandler);
|
||||
}
|
||||
};
|
||||
|
||||
common.init.push(function() {
|
||||
$('body').on('keydown', common.controlEnterHandler);
|
||||
|
||||
if (!!{ JSON.stringify(user ? true : false)}) {
|
||||
$('#complete-zipline-or-basejump-dialog').on('keydown', common.modalControlEnterHandler);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
document.addEventListener('gitter-sidecar-ready', function(e) {
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var room = 'freecodecamp/help';
|
||||
var title;
|
||||
|
||||
if (challengeType === '4') {
|
||||
if (common.challengeType === '4') {
|
||||
room = 'freecodecamp/helpBasejumps';
|
||||
title = 'Basejump Help';
|
||||
}
|
||||
|
||||
if (challengeType === '3') {
|
||||
if (common.challengeType === '3') {
|
||||
room = 'freecodecamp/helpZiplines';
|
||||
title = 'Zipline Help';
|
||||
}
|
||||
@ -118,3 +128,4 @@ block content
|
||||
window.main.chat.createHelpChat(room, '#challenge-help-btn', title);
|
||||
}
|
||||
});
|
||||
include ../partials/challenge-footer
|
||||
|
@ -37,17 +37,17 @@ block content
|
||||
.spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-12.col-md-4
|
||||
img.img-responsive.testimonial-image.img-center(src="http://i.imgur.com/xzDoJef.jpg", alt="Ashley's testimonial image")
|
||||
p.testimonial-copy Free Code Camp helped me get my first engineering job. This amazing community made my career switch a lot easier and more fun.
|
||||
h3 - Ashley Drake
|
||||
img.img-responsive.testimonial-image.img-center(src="http://i.imgur.com/nsvNixW.jpg", alt="Meta's testimonial image")
|
||||
p.testimonial-copy Through Free Code Camp, I built a robust and highly functional web app for a nonprofit. This led me to getting a fantastic job.
|
||||
h3 - Meta Hirschl
|
||||
.col-xs-12.col-sm-12.col-md-4
|
||||
img.img-responsive.testimonial-image.img-center(src="http://i.imgur.com/QPpjPac.jpg", alt="Brian's testimonial image")
|
||||
p.testimonial-copy Free Code Camp's a great way for disabled veterans like me to retrain. I'm receiving engineering job offers, and I haven't even finished yet.
|
||||
h3 - Brian Grant
|
||||
.col-xs-12.col-sm-12.col-md-4
|
||||
img.img-responsive.testimonial-image.img-center(src="http://i.imgur.com/wjlDigg.jpg", alt="Maxim Orlov's testimonial image")
|
||||
p.testimonial-copy I started Free Code Camp with zero knowledge of web development. 6 months later, I landed my first job as a back end engineer.
|
||||
h3 - Maxim Orlov
|
||||
.col-xs-12.col-sm-12.col-md-4
|
||||
img.img-responsive.testimonial-image.img-center(src="http://i.imgur.com/58XvKfe.jpg", alt="Meta's testimonial image")
|
||||
p.testimonial-copy Through Free Code Camp, I built a robust and highly functional web app for a nonprofit. This led me to getting a fantastic job.
|
||||
h3 - Meta Hirschl
|
||||
.spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2
|
||||
@ -87,9 +87,9 @@ block content
|
||||
.spacer
|
||||
hr
|
||||
.spacer
|
||||
h2 Here's why you should join our open source community right now:
|
||||
h3.col-xs-offset-0.col-sm-offset-1
|
||||
ul.text-left
|
||||
.col-xs-offset-0.col-sm-offset-1.text-left
|
||||
h2 Here's why you should join our open source community right now:
|
||||
ul.large-li
|
||||
li.ion-code   You'll get help in real time from our community chat rooms.
|
||||
li.ion-code   You'll meet up with other coders in your city.
|
||||
li.ion-code   You'll learn to code at your own pace, in your browser or on your phone.
|
||||
|
5
server/views/partials/challenge-footer.jade
Normal file
5
server/views/partials/challenge-footer.jade
Normal file
@ -0,0 +1,5 @@
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
script.
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('currentDashedName', typeof common !== 'undefined' && common.dashedName || '');
|
||||
}
|
@ -19,7 +19,3 @@
|
||||
h3 This will restore your code editor to its original state.
|
||||
a.btn.btn-lg.btn-info.btn-block#reset-button(href='#', data-dismiss='modal', aria-hidden='true') Clear my code
|
||||
a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Cancel
|
||||
script.
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('currentDashedName', typeof common !== 'undefined' && common.dashedName || dashedName || '');
|
||||
}
|
||||
|
@ -35,5 +35,4 @@ script.
|
||||
// Leave the below lines alone!
|
||||
script(src=rev('/js', 'main.js'))
|
||||
script(src="/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js")
|
||||
script(src="/bower_components/ramda/dist/ramda.min.js")
|
||||
script(src='/bower_components/lightbox2/dist/js/lightbox.min.js')
|
||||
|
@ -4,12 +4,17 @@ block content
|
||||
.text-center
|
||||
.row
|
||||
.col-xs-12
|
||||
h1.nonprofit-landing.hug-top Get pro bono code for your nonprofit
|
||||
h1.landing-heading Get pro bono code for your nonprofit.
|
||||
.big-break
|
||||
.col-xs-12.col-sm-12.col-md-12
|
||||
.embed-responsive.embed-responsive-16by9
|
||||
iframe.embed-responsive-item(src='//player.vimeo.com/video/126228100')
|
||||
.big-break
|
||||
h2 As featured in:
|
||||
img.img-center.img-responsive(src='https://s3.amazonaws.com/freecodecamp/as-seen-on.png')
|
||||
.spacer
|
||||
hr
|
||||
.spacer
|
||||
h2 Our process:
|
||||
.row
|
||||
.col-xs-12.col-sm-12.col-md-4
|
||||
@ -24,7 +29,9 @@ block content
|
||||
h3.nowrap Your solution
|
||||
img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_connect.svg.gz', alt='image of two people high-fiving')
|
||||
p.landing-p Together we'll set milestones and complete your project.
|
||||
.big-break
|
||||
.spacer
|
||||
hr
|
||||
.spacer
|
||||
h2 Solutions we can help you build:
|
||||
.text-center.negative-35
|
||||
.col-xs-12.col-sm-12.col-md-3
|
||||
@ -51,7 +58,20 @@ block content
|
||||
.col-xs-12.col-sm-12.col-md-3
|
||||
.landing-skill-icon.ion-settings
|
||||
h2.black-text ...and other tools
|
||||
.spacer
|
||||
hr
|
||||
.spacer
|
||||
.large-p.text-left.col-xs-offset-0.col-sm-offset-1
|
||||
h2 Our developers build projects for nonprofits who:
|
||||
ul.large-li
|
||||
li.ion-code   already have people who benefit from their services.
|
||||
li.ion-code   are registered with their government and have tax-exempt status.
|
||||
li.ion-code   have a stakeholder who can meet with our developers to direct the project.
|
||||
li.ion-code   can budget at least $20 per month for their own cloud servers.
|
||||
li.ion-code   can commit to using and maintaining the solution that our developers build.
|
||||
.big-break
|
||||
a.btn.btn-cta.signup-btn.btn-block(href="/nonprofits-form") My nonprofit needs coding help
|
||||
.button-spacer
|
||||
a.btn.btn-cta.btn-success.btn-block(href="/nonprofits/directory") Browse our directory of nonprofits we've helped
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2
|
||||
a.btn.btn-cta.signup-btn.btn-block(href="/nonprofits-form") My nonprofit needs coding help
|
||||
.button-spacer
|
||||
a.btn.btn-lg.btn-primary.btn-primary-ghost.btn-block(href="/nonprofits/directory") Browse our directory of nonprofits we've helped
|
||||
|
@ -15,15 +15,13 @@ block content
|
||||
|
|
||||
a.fa.fa-linkedin-square.text-primary(alt="#{story.camper}'s LinkedIn Profile", href=story.linkedin, target='_blank')
|
||||
p.text-justify= story.quote
|
||||
.col-xs-12.col-sm-10.col-sm-offset-1
|
||||
if moreStories
|
||||
.text-center
|
||||
a.btn.btn-lg.btn-primary.btn-primary-ghost.btn-block(href="/all-stories") Show more stories
|
||||
.spacer
|
||||
|
||||
|
||||
if moreStories
|
||||
.text-center
|
||||
a.btn.btn-lg.btn-primary.btn-primary-ghost.btn-block(href="/all-stories") Show more stories
|
||||
.spacer
|
||||
|
||||
|
||||
if !user
|
||||
.text-center
|
||||
a.btn.btn-cta.signup-btn(href="/login") Start learning to code (it's free)
|
||||
.spacer
|
||||
if !user
|
||||
.text-center
|
||||
a.btn.btn-cta.signup-btn.btn-block(href="/login") Start learning to code (it's free)
|
||||
.spacer
|
||||
|
@ -1,10 +1,7 @@
|
||||
.spacer
|
||||
.spacer
|
||||
#story-list.story-list
|
||||
|
||||
script(src="https://cdn.jsdelivr.net/ramda/0.10.0/ramda.min.js")
|
||||
script.
|
||||
|
||||
var getLinkedName = function getLinkedName(name) {
|
||||
return name.trim().toLowerCase().replace(/\s/g, '-');
|
||||
}
|
||||
|
@ -31,23 +31,23 @@ 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',
|
||||
{
|
||||
data: {
|
||||
searchValue: searchTerm
|
||||
}
|
||||
})
|
||||
.fail(function (xhr, textStatus, errorThrown) {
|
||||
$.post(url, { search: searchTerm })
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
$('#search-results').empty();
|
||||
var div = document.createElement("div");
|
||||
$(div).html("<h3 class='text-center text-warning dotted-underline'><em>No Results Found</em></h3>");
|
||||
$(div).appendTo($('#search-results'));
|
||||
})
|
||||
.done(function (data, textStatus, xhr) {
|
||||
.done(function(data, textStatus, xhr) {
|
||||
$('#search-results').empty();
|
||||
var spacer = document.createElement('div');
|
||||
$(spacer).html("<div class='spacer'></div>");
|
||||
|
@ -1,10 +1,12 @@
|
||||
.spacer
|
||||
.col-xs-12
|
||||
script.
|
||||
var storyURL = !{JSON.stringify(storyURL)};
|
||||
var storyTitle = !{JSON.stringify(storyTitle)};
|
||||
var storyImage = !{JSON.stringify(storyImage)};
|
||||
var storyMetaDescription = !{JSON.stringify(storyMetaDescription)};
|
||||
var main = window.main || { init: [] };
|
||||
main.storyURL = !{JSON.stringify(storyURL)};
|
||||
main.storyTitle = !{JSON.stringify(storyTitle)};
|
||||
main.storyImage = !{JSON.stringify(storyImage)};
|
||||
main.storyMetaDescription = !{JSON.stringify(storyMetaDescription)};
|
||||
|
||||
form.form-horizontal.control-label-story-submission#story-submission-form(name="submitStory")
|
||||
.col-xs-12
|
||||
.form-group
|
||||
|
Reference in New Issue
Block a user