Merge branch 'staging' into converge-bonfires
Conflicts: seed/challenges/basic-bonfires.json seed/challenges/intermediate-bonfires.json
This commit is contained in:
@ -4,7 +4,7 @@ import React from 'react';
|
||||
import Fetchr from 'fetchr';
|
||||
import debugFactory from 'debug';
|
||||
import { Router } from 'react-router';
|
||||
import { history } from 'react-router/lib/BrowserHistory';
|
||||
import { createLocation, createHistory } from 'history';
|
||||
import { hydrate } from 'thundercats';
|
||||
import { Render } from 'thundercats-react';
|
||||
|
||||
@ -18,21 +18,29 @@ const services = new Fetchr({
|
||||
});
|
||||
|
||||
Rx.config.longStackSupport = !!debug.enabled;
|
||||
|
||||
const history = createHistory();
|
||||
const appLocation = createLocation(
|
||||
location.pathname + location.search
|
||||
);
|
||||
// returns an observable
|
||||
app$(history)
|
||||
app$({ history, location: appLocation })
|
||||
.flatMap(
|
||||
({ AppCat }) => {
|
||||
// instantiate the cat with service
|
||||
const appCat = AppCat(null, services);
|
||||
// hydrate the stores
|
||||
return hydrate(appCat, catState)
|
||||
.map(() => appCat);
|
||||
},
|
||||
({ initialState }, appCat) => ({ initialState, appCat })
|
||||
// not using nextLocation at the moment but will be used for
|
||||
// redirects in the future
|
||||
({ nextLocation, props }, appCat) => ({ nextLocation, props, appCat })
|
||||
)
|
||||
.flatMap(({ initialState, appCat }) => {
|
||||
.flatMap(({ props, appCat }) => {
|
||||
props.history = history;
|
||||
return Render(
|
||||
appCat,
|
||||
React.createElement(Router, initialState),
|
||||
React.createElement(Router, props),
|
||||
DOMContianer
|
||||
);
|
||||
})
|
||||
|
@ -1,3 +1,32 @@
|
||||
var mapShareKey = 'map-shares';
|
||||
var lastCompleted = typeof lastCompleted !== 'undefined' ?
|
||||
lastCompleted :
|
||||
'';
|
||||
|
||||
function getMapShares() {
|
||||
var alreadyShared = JSON.parse(localStorage.getItem(mapShareKey) || '[]');
|
||||
if (!alreadyShared || !Array.isArray(alreadyShared)) {
|
||||
localStorage.setItem(mapShareKey, JSON.stringify([]));
|
||||
alreadyShared = [];
|
||||
}
|
||||
return alreadyShared;
|
||||
}
|
||||
|
||||
function setMapShare(id) {
|
||||
var alreadyShared = getMapShares();
|
||||
var found = false;
|
||||
alreadyShared.forEach(function(_id) {
|
||||
if (_id === id) {
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
if (!found) {
|
||||
alreadyShared.push(id);
|
||||
}
|
||||
localStorage.setItem(mapShareKey, JSON.stringify(alreadyShared));
|
||||
return alreadyShared;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
var challengeName = typeof challengeName !== 'undefined' ?
|
||||
@ -383,6 +412,40 @@ $(document).ready(function() {
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
||||
// map sharing
|
||||
var alreadyShared = getMapShares();
|
||||
|
||||
if (lastCompleted && alreadyShared.indexOf(lastCompleted) === -1) {
|
||||
$('div[id="' + lastCompleted + '"]')
|
||||
.parent()
|
||||
.parent()
|
||||
.removeClass('hidden');
|
||||
}
|
||||
|
||||
// on map view
|
||||
$('.map-challenge-block-share').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var challengeBlockName = $(this).children().attr('id');
|
||||
var challengeBlockEscapedName = challengeBlockName.replace(/\s/, '%20');
|
||||
var username = typeof window.username !== 'undefined' ?
|
||||
window.username :
|
||||
'';
|
||||
|
||||
var link = 'https://www.facebook.com/dialog/feed?' +
|
||||
'app_id=1644598365767721' +
|
||||
'&display=page&' +
|
||||
'caption=I%20just%20completed%20the%20' +
|
||||
challengeBlockEscapedName +
|
||||
'%20section%20on%20Free%20Code%20Camp%2E' +
|
||||
'&link=http%3A%2F%2Ffreecodecamp%2Ecom%2F' +
|
||||
username +
|
||||
'&redirect_uri=http%3A%2F%2Ffreecodecamp%2Ecom%2Fmap';
|
||||
|
||||
setMapShare(challengeBlockName);
|
||||
window.location.href = link;
|
||||
});
|
||||
});
|
||||
|
||||
function defCheck(a){
|
||||
|
@ -1,17 +1,17 @@
|
||||
import Rx from 'rx';
|
||||
import { Router } from 'react-router';
|
||||
import { match } from 'react-router';
|
||||
import App from './App.jsx';
|
||||
import AppCat from './Cat';
|
||||
|
||||
import childRoutes from './routes';
|
||||
|
||||
const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
|
||||
const route$ = Rx.Observable.fromNodeCallback(match);
|
||||
|
||||
const routes = Object.assign({ components: App }, childRoutes);
|
||||
|
||||
export default function app$(location) {
|
||||
return router$(routes, location)
|
||||
.map(([initialState, transistion]) => {
|
||||
return { initialState, transistion, AppCat };
|
||||
export default function app$({ location, history }) {
|
||||
return route$({ routes, location, history })
|
||||
.map(([nextLocation, props]) => {
|
||||
return { nextLocation, props, AppCat };
|
||||
});
|
||||
}
|
||||
|
43
common/app/routes/Jobs/components/CreateJobModal.jsx
Normal file
43
common/app/routes/Jobs/components/CreateJobModal.jsx
Normal file
@ -0,0 +1,43 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { History } from 'react-router';
|
||||
import { Button, Modal } from 'react-bootstrap';
|
||||
|
||||
export default React.createClass({
|
||||
displayName: 'CreateJobsModal',
|
||||
|
||||
propTypes: {
|
||||
onHide: PropTypes.func,
|
||||
showModal: PropTypes.bool
|
||||
},
|
||||
|
||||
mixins: [History],
|
||||
|
||||
goToNewJob(onHide) {
|
||||
onHide();
|
||||
this.history.pushState(null, '/jobs/new');
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
showModal,
|
||||
onHide
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onHide={ onHide }
|
||||
show={ showModal }>
|
||||
<Modal.Body>
|
||||
<h4>Welcome to Free Code Camp's board</h4>
|
||||
<p>We post jobs specifically target to our junior developers.</p>
|
||||
<Button
|
||||
block={ true }
|
||||
className='signup-btn'
|
||||
onClick={ () => this.goToNewJob(onHide) }>
|
||||
Post a Job
|
||||
</Button>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
});
|
@ -1,7 +1,9 @@
|
||||
import React, { cloneElement, PropTypes } from 'react';
|
||||
import { contain } from 'thundercats-react';
|
||||
import { Navigation } from 'react-router';
|
||||
import { History } from 'react-router';
|
||||
import { Button, Jumbotron, Row } from 'react-bootstrap';
|
||||
|
||||
import CreateJobModal from './CreateJobModal.jsx';
|
||||
import ListJobs from './List.jsx';
|
||||
|
||||
export default contain(
|
||||
@ -13,12 +15,14 @@ export default contain(
|
||||
React.createClass({
|
||||
displayName: 'Jobs',
|
||||
|
||||
mixins: [History],
|
||||
|
||||
propTypes: {
|
||||
children: PropTypes.element,
|
||||
jobActions: PropTypes.object,
|
||||
jobs: PropTypes.array
|
||||
jobs: PropTypes.array,
|
||||
showModal: PropTypes.bool
|
||||
},
|
||||
mixins: [Navigation],
|
||||
|
||||
handleJobClick(id) {
|
||||
const { jobActions } = this.props;
|
||||
@ -26,7 +30,7 @@ export default contain(
|
||||
return null;
|
||||
}
|
||||
jobActions.findJob(id);
|
||||
this.transitionTo(`/jobs/${id}`);
|
||||
this.history.pushState(null, `/jobs/${id}`);
|
||||
},
|
||||
|
||||
renderList(handleJobClick, jobs) {
|
||||
@ -48,7 +52,12 @@ export default contain(
|
||||
},
|
||||
|
||||
render() {
|
||||
const { children, jobs } = this.props;
|
||||
const {
|
||||
children,
|
||||
jobs,
|
||||
showModal,
|
||||
jobActions
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -62,7 +71,8 @@ export default contain(
|
||||
</p>
|
||||
<Button
|
||||
bsSize='large'
|
||||
className='signup-btn'>
|
||||
className='signup-btn'
|
||||
onClick={ jobActions.openModal }>
|
||||
Try the first month 20% off!
|
||||
</Button>
|
||||
</Jumbotron>
|
||||
@ -71,6 +81,9 @@ export default contain(
|
||||
{ this.renderChild(children, jobs) ||
|
||||
this.renderList(this.handleJobClick, jobs) }
|
||||
</Row>
|
||||
<CreateJobModal
|
||||
onHide={ jobActions.closeModal }
|
||||
showModal={ showModal } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ export default React.createClass({
|
||||
id,
|
||||
company,
|
||||
position,
|
||||
isHighlighted,
|
||||
description,
|
||||
logo,
|
||||
city,
|
||||
@ -44,6 +45,7 @@ export default React.createClass({
|
||||
);
|
||||
return (
|
||||
<Panel
|
||||
bsStyle={ isHighlighted ? 'warning' : 'default' }
|
||||
collapsible={ true }
|
||||
eventKey={ index }
|
||||
header={ header }
|
||||
|
319
common/app/routes/Jobs/components/NewJob.jsx
Normal file
319
common/app/routes/Jobs/components/NewJob.jsx
Normal file
@ -0,0 +1,319 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { History } from 'react-router';
|
||||
import { contain } from 'thundercats-react';
|
||||
import debugFactory from 'debug';
|
||||
import { getDefaults } from '../utils';
|
||||
|
||||
import {
|
||||
inHTMLData,
|
||||
uriInSingleQuotedAttr
|
||||
} from 'xss-filters';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Input,
|
||||
Row,
|
||||
Well
|
||||
} from 'react-bootstrap';
|
||||
|
||||
import {
|
||||
isAscii,
|
||||
isEmail,
|
||||
isMobilePhone,
|
||||
isURL
|
||||
} from 'validator';
|
||||
|
||||
const debug = debugFactory('freecc:jobs:newForm');
|
||||
|
||||
const checkValidity = [
|
||||
'position',
|
||||
'locale',
|
||||
'description',
|
||||
'email',
|
||||
'phone',
|
||||
'url',
|
||||
'logo',
|
||||
'name',
|
||||
'highlight'
|
||||
];
|
||||
|
||||
function formatValue(value, validator, type = 'string') {
|
||||
const formated = getDefaults(type);
|
||||
if (validator && type === 'string') {
|
||||
formated.valid = validator(value);
|
||||
}
|
||||
if (value) {
|
||||
formated.value = value;
|
||||
formated.bsStyle = formated.valid ? 'success' : 'error';
|
||||
}
|
||||
return formated;
|
||||
}
|
||||
|
||||
function isValidURL(data) {
|
||||
return isURL(data, { 'require_protocol': true });
|
||||
}
|
||||
|
||||
function isValidPhone(data) {
|
||||
return isMobilePhone(data, 'en-US');
|
||||
}
|
||||
|
||||
export default contain({
|
||||
actions: 'jobActions',
|
||||
store: 'jobsStore',
|
||||
map({ form = {} }) {
|
||||
const {
|
||||
position,
|
||||
locale,
|
||||
description,
|
||||
email,
|
||||
phone,
|
||||
url,
|
||||
logo,
|
||||
name,
|
||||
highlight
|
||||
} = form;
|
||||
return {
|
||||
position: formatValue(position, isAscii),
|
||||
locale: formatValue(locale, isAscii),
|
||||
description: formatValue(description, isAscii),
|
||||
email: formatValue(email, isEmail),
|
||||
phone: formatValue(phone, isValidPhone),
|
||||
url: formatValue(url, isValidURL),
|
||||
logo: formatValue(logo, isValidURL),
|
||||
name: formatValue(name, isAscii),
|
||||
highlight: formatValue(highlight, null, 'bool')
|
||||
};
|
||||
},
|
||||
subscribeOnWillMount() {
|
||||
return typeof window !== 'undefined';
|
||||
}
|
||||
},
|
||||
React.createClass({
|
||||
displayName: 'NewJob',
|
||||
|
||||
propTypes: {
|
||||
jobActions: PropTypes.object,
|
||||
position: PropTypes.object,
|
||||
locale: PropTypes.object,
|
||||
description: PropTypes.object,
|
||||
email: PropTypes.object,
|
||||
phone: PropTypes.object,
|
||||
url: PropTypes.object,
|
||||
logo: PropTypes.object,
|
||||
name: PropTypes.object,
|
||||
highlight: PropTypes.object
|
||||
},
|
||||
|
||||
mixins: [History],
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const props = 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 (!valid) {
|
||||
debug('form not valid');
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
position,
|
||||
locale,
|
||||
description,
|
||||
email,
|
||||
phone,
|
||||
url,
|
||||
logo,
|
||||
name,
|
||||
highlight,
|
||||
jobActions
|
||||
} = this.props;
|
||||
|
||||
// sanitize user output
|
||||
const jobValues = {
|
||||
position: inHTMLData(position.value),
|
||||
location: inHTMLData(locale.value),
|
||||
description: inHTMLData(description.value),
|
||||
email: inHTMLData(email.value),
|
||||
phone: inHTMLData(phone.value),
|
||||
url: uriInSingleQuotedAttr(url.value),
|
||||
logo: uriInSingleQuotedAttr(logo.value),
|
||||
name: inHTMLData(name.value),
|
||||
highlight: !!highlight.value
|
||||
};
|
||||
|
||||
const job = Object.keys(jobValues).reduce((accu, prop) => {
|
||||
if (jobValues[prop]) {
|
||||
accu[prop] = jobValues[prop];
|
||||
}
|
||||
return accu;
|
||||
}, {});
|
||||
|
||||
job.postedOn = new Date();
|
||||
debug('job sanitized', job);
|
||||
jobActions.saveForm(job);
|
||||
|
||||
this.history.pushState(null, '/jobs/new/preview');
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
const { jobActions } = this.props;
|
||||
jobActions.getSavedForm();
|
||||
},
|
||||
|
||||
handleChange(name, { target: { value } }) {
|
||||
const { jobActions: { handleForm } } = this.props;
|
||||
handleForm({ [name]: value });
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
position,
|
||||
locale,
|
||||
description,
|
||||
email,
|
||||
phone,
|
||||
url,
|
||||
logo,
|
||||
name,
|
||||
highlight,
|
||||
jobActions: { handleForm }
|
||||
} = this.props;
|
||||
const { handleChange } = this;
|
||||
const labelClass = 'col-sm-offset-1 col-sm-2';
|
||||
const inputClass = 'col-sm-6';
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<Col>
|
||||
<Well className='text-center'>
|
||||
<h1>Create Your Job Post</h1>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
onSubmit={ this.handleSubmit }>
|
||||
|
||||
<div className='spacer'>
|
||||
<h2>Job Information</h2>
|
||||
</div>
|
||||
<Input
|
||||
bsStyle={ position.bsStyle }
|
||||
label='Position'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('position', e) }
|
||||
placeholder='Position'
|
||||
type='text'
|
||||
value={ position.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
bsStyle={ locale.bsStyle }
|
||||
label='Location'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('locale', e) }
|
||||
placeholder='Location'
|
||||
type='text'
|
||||
value={ locale.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
bsStyle={ description.bsStyle }
|
||||
label='Description'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('description', e) }
|
||||
placeholder='Description'
|
||||
rows='10'
|
||||
type='textarea'
|
||||
value={ description.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
|
||||
<div className='divider'>
|
||||
<h2>Company Information</h2>
|
||||
</div>
|
||||
<Input
|
||||
bsStyle={ name.bsStyle }
|
||||
label='Company Name'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('name', e) }
|
||||
placeholder='Foo, INC'
|
||||
type='text'
|
||||
value={ name.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
bsStyle={ email.bsStyle }
|
||||
label='Email'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('email', e) }
|
||||
placeholder='Email'
|
||||
type='email'
|
||||
value={ email.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
bsStyle={ phone.bsStyle }
|
||||
label='Phone'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('phone', e) }
|
||||
placeholder='555-123-1234'
|
||||
type='tel'
|
||||
value={ phone.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
bsStyle={ url.bsStyle }
|
||||
label='URL'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('url', e) }
|
||||
placeholder='http://freecatphotoapp.com'
|
||||
type='url'
|
||||
value={ url.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
<Input
|
||||
bsStyle={ logo.bsStyle }
|
||||
label='Logo'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => handleChange('logo', e) }
|
||||
placeholder='http://freecatphotoapp.com/logo.png'
|
||||
type='url'
|
||||
value={ logo.value }
|
||||
wrapperClassName={ inputClass } />
|
||||
|
||||
<div className='divider'>
|
||||
<h2>Make it stand out</h2>
|
||||
</div>
|
||||
<Input
|
||||
checked={ highlight.value }
|
||||
label='Highlight your ad'
|
||||
labelClassName={ 'col-sm-offset-1 col-sm-6'}
|
||||
onChange={
|
||||
({ target: { checked } }) => handleForm({
|
||||
highlight: !!checked
|
||||
})
|
||||
}
|
||||
type='checkbox' />
|
||||
<div className='spacer' />
|
||||
<Row>
|
||||
<Col
|
||||
lg={ 6 }
|
||||
lgOffset={ 3 }>
|
||||
<Button
|
||||
block={ true }
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
type='submit'>
|
||||
Preview My Ad
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
</Well>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
14
common/app/routes/Jobs/components/Preview.jsx
Normal file
14
common/app/routes/Jobs/components/Preview.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
// import React, { PropTypes } from 'react';
|
||||
import { contain } from 'thundercats-react';
|
||||
import ShowJob from './ShowJob.jsx';
|
||||
|
||||
export default contain(
|
||||
{
|
||||
store: 'JobsStore',
|
||||
actions: 'JobActions',
|
||||
map({ form: job = {} }) {
|
||||
return { job };
|
||||
}
|
||||
},
|
||||
ShowJob
|
||||
);
|
@ -1,13 +1,5 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { contain } from 'thundercats-react';
|
||||
import { Row, Thumbnail, Panel, Well } from 'react-bootstrap';
|
||||
import moment from 'moment';
|
||||
|
||||
const thumbnailStyle = {
|
||||
backgroundColor: 'white',
|
||||
maxHeight: '100px',
|
||||
maxWidth: '100px'
|
||||
};
|
||||
import ShowJob from './ShowJob.jsx';
|
||||
|
||||
export default contain(
|
||||
{
|
||||
@ -28,61 +20,5 @@ export default contain(
|
||||
return job.id !== id;
|
||||
}
|
||||
},
|
||||
React.createClass({
|
||||
displayName: 'ShowJob',
|
||||
propTypes: {
|
||||
job: PropTypes.object,
|
||||
params: PropTypes.object
|
||||
},
|
||||
|
||||
renderHeader({ company, position }) {
|
||||
return (
|
||||
<div>
|
||||
<h4 style={{ display: 'inline-block' }}>{ company }</h4>
|
||||
<h5
|
||||
className='pull-right hidden-xs hidden-md'
|
||||
style={{ display: 'inline-block' }}>
|
||||
{ position }
|
||||
</h5>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { job = {} } = this.props;
|
||||
const {
|
||||
logo,
|
||||
position,
|
||||
city,
|
||||
company,
|
||||
state,
|
||||
email,
|
||||
phone,
|
||||
postedOn,
|
||||
description
|
||||
} = job;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<Well>
|
||||
<Thumbnail
|
||||
alt={ company + 'company logo' }
|
||||
src={ logo }
|
||||
style={ thumbnailStyle } />
|
||||
<Panel>
|
||||
Position: { position }
|
||||
Location: { city }, { state }
|
||||
<br />
|
||||
Contact: { email || phone || 'N/A' }
|
||||
<br />
|
||||
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
|
||||
</Panel>
|
||||
<p>{ description }</p>
|
||||
</Well>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})
|
||||
ShowJob
|
||||
);
|
||||
|
67
common/app/routes/Jobs/components/ShowJob.jsx
Normal file
67
common/app/routes/Jobs/components/ShowJob.jsx
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Row, Thumbnail, Panel, Well } from 'react-bootstrap';
|
||||
import moment from 'moment';
|
||||
|
||||
const thumbnailStyle = {
|
||||
backgroundColor: 'white',
|
||||
maxHeight: '100px',
|
||||
maxWidth: '100px'
|
||||
};
|
||||
|
||||
export default React.createClass({
|
||||
displayName: 'ShowJob',
|
||||
propTypes: {
|
||||
job: PropTypes.object,
|
||||
params: PropTypes.object
|
||||
},
|
||||
|
||||
renderHeader({ company, position }) {
|
||||
return (
|
||||
<div>
|
||||
<h4 style={{ display: 'inline-block' }}>{ company }</h4>
|
||||
<h5
|
||||
className='pull-right hidden-xs hidden-md'
|
||||
style={{ display: 'inline-block' }}>
|
||||
{ position }
|
||||
</h5>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { job = {} } = this.props;
|
||||
const {
|
||||
logo,
|
||||
position,
|
||||
city,
|
||||
company,
|
||||
state,
|
||||
email,
|
||||
phone,
|
||||
postedOn,
|
||||
description
|
||||
} = job;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<Well>
|
||||
<Thumbnail
|
||||
alt={ company + 'company logo' }
|
||||
src={ logo }
|
||||
style={ thumbnailStyle } />
|
||||
<Panel>
|
||||
Position: { position }
|
||||
Location: { city }, { state }
|
||||
<br />
|
||||
Contact: { email || phone || 'N/A' }
|
||||
<br />
|
||||
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
|
||||
</Panel>
|
||||
<p>{ description }</p>
|
||||
</Well>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
@ -1,7 +1,9 @@
|
||||
import { Actions } from 'thundercats';
|
||||
import store from 'store';
|
||||
import debugFactory from 'debug';
|
||||
|
||||
const debug = debugFactory('freecc:jobs:actions');
|
||||
const assign = Object.assign;
|
||||
|
||||
export default Actions({
|
||||
setJobs: null,
|
||||
@ -23,7 +25,7 @@ export default Actions({
|
||||
|
||||
// if no job found this will be null which is a op noop
|
||||
return foundJob ?
|
||||
Object.assign({}, oldState, { currentJob: foundJob }) :
|
||||
assign({}, oldState, { currentJob: foundJob }) :
|
||||
null;
|
||||
};
|
||||
},
|
||||
@ -31,6 +33,31 @@ export default Actions({
|
||||
getJob: null,
|
||||
getJobs(params) {
|
||||
return { params };
|
||||
},
|
||||
openModal() {
|
||||
return { showModal: true };
|
||||
},
|
||||
closeModal() {
|
||||
return { showModal: false };
|
||||
},
|
||||
handleForm(value) {
|
||||
return {
|
||||
transform(oldState) {
|
||||
const { form } = oldState;
|
||||
const newState = assign({}, oldState);
|
||||
newState.form = assign(
|
||||
{},
|
||||
form,
|
||||
value
|
||||
);
|
||||
return newState;
|
||||
}
|
||||
};
|
||||
},
|
||||
saveForm: null,
|
||||
getSavedForm: null,
|
||||
setForm(form) {
|
||||
return { form };
|
||||
}
|
||||
})
|
||||
.refs({ displayName: 'JobActions' })
|
||||
@ -56,8 +83,22 @@ export default Actions({
|
||||
debug('job services experienced an issue', err);
|
||||
return jobActions.setError({ err });
|
||||
}
|
||||
if (job) {
|
||||
jobActions.setJobs({ currentJob: job });
|
||||
}
|
||||
jobActions.setJobs({});
|
||||
});
|
||||
});
|
||||
|
||||
jobActions.saveForm.subscribe((form) => {
|
||||
store.set('newJob', form);
|
||||
});
|
||||
|
||||
jobActions.getSavedForm.subscribe(() => {
|
||||
const job = store.get('newJob');
|
||||
if (job && !Array.isArray(job) && typeof job === 'object') {
|
||||
jobActions.setForm(job);
|
||||
}
|
||||
});
|
||||
return jobActions;
|
||||
});
|
||||
|
@ -6,12 +6,25 @@ const {
|
||||
transformer
|
||||
} = Store;
|
||||
|
||||
export default Store()
|
||||
export default Store({ showModal: false })
|
||||
.refs({ displayName: 'JobsStore' })
|
||||
.init(({ instance: jobsStore, args: [cat] }) => {
|
||||
const { setJobs, findJob, setError } = cat.getActions('JobActions');
|
||||
const {
|
||||
setJobs,
|
||||
findJob,
|
||||
setError,
|
||||
openModal,
|
||||
closeModal,
|
||||
handleForm,
|
||||
setForm
|
||||
} = cat.getActions('JobActions');
|
||||
const register = createRegistrar(jobsStore);
|
||||
register(setter(setJobs));
|
||||
register(transformer(findJob));
|
||||
register(setter(setError));
|
||||
register(setter(openModal));
|
||||
register(setter(closeModal));
|
||||
register(setter(setForm));
|
||||
|
||||
register(transformer(findJob));
|
||||
register(handleForm);
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import Jobs from './components/Jobs.jsx';
|
||||
import NewJob from './components/NewJob.jsx';
|
||||
import Show from './components/Show.jsx';
|
||||
import Preview from './components/Preview.jsx';
|
||||
|
||||
/*
|
||||
* index: /jobs list jobs
|
||||
@ -11,6 +13,12 @@ export default {
|
||||
childRoutes: [{
|
||||
path: '/jobs',
|
||||
component: Jobs
|
||||
}, {
|
||||
path: 'jobs/new',
|
||||
component: NewJob
|
||||
}, {
|
||||
path: 'jobs/new/preview',
|
||||
component: Preview
|
||||
}, {
|
||||
path: 'jobs/:id',
|
||||
component: Show
|
||||
|
22
common/app/routes/Jobs/utils.js
Normal file
22
common/app/routes/Jobs/utils.js
Normal file
@ -0,0 +1,22 @@
|
||||
const defaults = {
|
||||
'string': {
|
||||
value: '',
|
||||
valid: false,
|
||||
pristine: true,
|
||||
type: 'string'
|
||||
},
|
||||
bool: {
|
||||
value: false,
|
||||
type: 'boolean'
|
||||
}
|
||||
};
|
||||
|
||||
export function getDefaults(type, value) {
|
||||
if (!type) {
|
||||
return defaults['string'];
|
||||
}
|
||||
if (value) {
|
||||
return Object.assign({}, defaults[type], { value });
|
||||
}
|
||||
return Object.assign({}, defaults[type]);
|
||||
}
|
@ -3,12 +3,8 @@ import Hikes from './Hikes';
|
||||
|
||||
export default {
|
||||
path: '/',
|
||||
getChildRoutes(locationState, cb) {
|
||||
setTimeout(() => {
|
||||
cb(null, [
|
||||
childRoutes: [
|
||||
Jobs,
|
||||
Hikes
|
||||
]);
|
||||
}, 0);
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "job",
|
||||
"base": "PersistedModel",
|
||||
"strict": true,
|
||||
"idInjection": true,
|
||||
"trackChanges": false,
|
||||
"properties": {
|
||||
@ -29,6 +30,9 @@
|
||||
"state": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"country": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -38,7 +42,7 @@
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"isApproverd": {
|
||||
"isApproved": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isHighlighted": {
|
||||
|
@ -34,10 +34,6 @@
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalStoryAuthorEmail": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"rank": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
|
@ -157,6 +157,9 @@
|
||||
"rand": {
|
||||
"type": "number",
|
||||
"index": true
|
||||
},
|
||||
"tshirtVote": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
|
@ -49,6 +49,7 @@ var paths = {
|
||||
'!public/js/bundle*',
|
||||
'node_modules/',
|
||||
'client/',
|
||||
'seed',
|
||||
'server/manifests/*.json',
|
||||
'server/rev-manifest.json'
|
||||
],
|
||||
|
10
package.json
10
package.json
@ -58,10 +58,10 @@
|
||||
"gulp-webpack": "^1.5.0",
|
||||
"helmet": "~0.9.0",
|
||||
"helmet-csp": "^0.2.3",
|
||||
"history": "^1.9.0",
|
||||
"jade": "~1.8.0",
|
||||
"json-loader": "^0.5.2",
|
||||
"less": "~1.7.5",
|
||||
"less-middleware": "~2.0.1",
|
||||
"less": "~2.5.1",
|
||||
"lodash": "^3.9.3",
|
||||
"loopback": "https://github.com/FreeCodeCamp/loopback.git#fix/no-password",
|
||||
"loopback-boot": "2.8.2",
|
||||
@ -89,7 +89,7 @@
|
||||
"react": "^0.13.3",
|
||||
"react-bootstrap": "~0.23.7",
|
||||
"react-motion": "~0.1.0",
|
||||
"react-router": "https://github.com/BerkeleyTrue/react-router#freecodecamp",
|
||||
"react-router": "^1.0.0-rc1",
|
||||
"react-vimeo": "^0.0.3",
|
||||
"request": "~2.53.0",
|
||||
"rev-del": "^1.0.5",
|
||||
@ -97,12 +97,14 @@
|
||||
"sanitize-html": "~1.6.1",
|
||||
"sort-keys": "^1.1.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"store": "https://github.com/berkeleytrue/store.js.git#feature/noop-server",
|
||||
"thundercats": "^2.1.0",
|
||||
"thundercats-react": "^0.1.0",
|
||||
"twit": "~1.1.20",
|
||||
"uglify-js": "~2.4.15",
|
||||
"validator": "~3.22.1",
|
||||
"validator": "^3.22.1",
|
||||
"webpack": "^1.9.12",
|
||||
"xss-filters": "^1.2.6",
|
||||
"yui": "~3.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -520,7 +520,7 @@
|
||||
"challengeSeed":[
|
||||
"var ourArray = [1,2,3];",
|
||||
"ourArray[1] = 3;",
|
||||
"// ourArray[1] now equals [1,3,3].",
|
||||
"// ourArray now equals [1,3,3].",
|
||||
"var myArray = [1,2,3];",
|
||||
"// Only change code below this line.",
|
||||
"",
|
||||
@ -643,8 +643,9 @@
|
||||
"challengeSeed": [
|
||||
"var ourArray = [\"Stimpson\", \"J\", [\"cat\"]];",
|
||||
"ourArray.shift();",
|
||||
"// ourArray now equals [\"happy\", \"J\", [\"cat\"]]",
|
||||
"// ourArray now equals [\"J\", [\"cat\"]]",
|
||||
"ourArray.unshift(\"happy\");",
|
||||
"// ourArray now equals [\"happy\", \"J\", [\"cat\"]]",
|
||||
"",
|
||||
"var myArray = [\"John\", 23, [\"dog\", 3]];",
|
||||
"myArray.shift();",
|
||||
|
@ -1142,7 +1142,8 @@
|
||||
"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.')",
|
||||
"assert($(\"p\").text().match(/View\\smore/gi), 'Your <code>p</code> element should have the text \"View more\".')",
|
||||
"assert($(\"p\").text().match(/^View\\smore\\s/gi), 'Your <code>p</code> element should have the text \"View more \" (with a space after it).')",
|
||||
"assert(!$(\"a\").text().match(/View\\smore/gi), 'Your <code>a</code> element should <em>not</em> have the text \"View more\".')",
|
||||
"assert(editor.match(/<\\/p>/g) && 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(editor.match(/<\\/a>/g) && editor.match(/<a/g) && editor.match(/<\\/a>/g).length === editor.match(/<a/g).length, 'Make sure each of your <code>a</code> elements has a closing tag.')"
|
||||
],
|
||||
|
@ -61,6 +61,7 @@
|
||||
"diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert(typeof(diff([1, 2, 3, 5], [1, 2, 3, 4, 5])) === \"object\", 'message: <code>diff()</code> should return an array.');",
|
||||
"assert.deepEqual(diff([\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"pink wool\"], 'message: <code>[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]</code> should return <code>[\"pink wool\"]</code>.');",
|
||||
"assert.includeMembers(diff([\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"diorite\", \"pink wool\"], 'message: <code>[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]</code> should return <code>[\"diorite\", \"pink wool\"]</code>.');",
|
||||
@ -68,6 +69,15 @@
|
||||
"assert.deepEqual(diff([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], 'message: <code>[1, 2, 3, 5], [1, 2, 3, 4, 5]</code> should return <code>[4]</code>.');",
|
||||
"assert.includeMembers(diff([1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]), [\"piglet\", 4], 'message: <code>[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]</code> should return <code>[\"piglet\", 4]</code>.');",
|
||||
"assert.deepEqual(diff([], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]), [\"snuffleupagus\", \"cookie monster\", \"elmo\"], 'message: <code>[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]</code> should return <code>[\"snuffleupagus\", \"cookie monster\", \"elmo\"]</code>.');"
|
||||
=======
|
||||
"assert(typeof(diff([1, 2, 3, 5], [1, 2, 3, 4, 5])) === \"object\", 'The result should be an array.');",
|
||||
"assert.deepEqual(diff(['diorite', 'andesite', 'grass', 'dirt', 'pink wool', 'dead shrub'], ['diorite', 'andesite', 'grass', 'dirt', 'dead shrub']), ['pink wool'], 'arrays with only one difference');",
|
||||
"assert.includeMembers(diff(['andesite', 'grass', 'dirt', 'pink wool', 'dead shrub'], ['diorite', 'andesite', 'grass', 'dirt', 'dead shrub']), ['diorite', 'pink wool'], 'arrays with more than one difference');",
|
||||
"assert.deepEqual(diff(['andesite', 'grass', 'dirt', 'dead shrub'], ['andesite', 'grass', 'dirt', 'dead shrub']), [], 'arrays with no difference');",
|
||||
"assert.deepEqual(diff([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], 'arrays with numbers');",
|
||||
"assert.includeMembers(diff([1, 'calf', 3, 'piglet'], [1, 'calf', 3, 4]), ['piglet', 4], 'arrays with numbers and strings');",
|
||||
"assert.deepEqual(diff([], ['snuffleupagus', 'cookie monster', 'elmo']), ['snuffleupagus', 'cookie monster', 'elmo'], 'empty array');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Comparison Operators",
|
||||
@ -93,11 +103,19 @@
|
||||
"id": "a7f4d8f2483413a6ce226cac",
|
||||
"title": "Roman Numeral Converter",
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(convert(12), \"XII\", 'message: <code>convert(12)</code> should return \"XII\".');",
|
||||
"assert.deepEqual(convert(5), \"V\", 'message: <code>convert(5)</code> should return \"V\".');",
|
||||
"assert.deepEqual(convert(9), \"IX\", 'message: <code>convert(9)</code> should return \"IX\".');",
|
||||
"assert.deepEqual(convert(29), \"XXIX\", 'message: <code>convert(29)</code> should return \"XXIX\".');",
|
||||
"assert.deepEqual(convert(16), \"XVI\", 'message: <code>convert(16)</code> should return \"XVI\".');"
|
||||
=======
|
||||
"assert.deepEqual(convert(12), \"XII\", '<code>convert(12)</code> should return \"XII\"');",
|
||||
"assert.deepEqual(convert(5), \"V\", '<code>convert(5)</code> should return \"V\"');",
|
||||
"assert.deepEqual(convert(9), \"IX\", '<code>convert(9)</code> should return \"IX\"');",
|
||||
"assert.deepEqual(convert(29), \"XXIX\", '<code>convert(29)</code> should return \"XXIX\"');",
|
||||
"assert.deepEqual(convert(16), \"XVI\", '<code>convert(16)</code> should return \"XVI\"');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"difficulty": "2.02",
|
||||
"description": [
|
||||
@ -150,9 +168,16 @@
|
||||
"where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" });"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }), [{ first: \"Tybalt\", last: \"Capulet\" }], 'message: <code>where()</code> should return an array of objects.');",
|
||||
"assert.deepEqual(where([{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], { \"a\": 1 }), [{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], 'message: <code>where([{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], { \"a\": 1 })</code> should return <code>[{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }]</code>.');",
|
||||
"assert.deepEqual(where([{ \"a\": 1, \"b\": 2 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], { \"a\": 1, \"b\": 2 }), [{ \"a\": 1, \"b\": 2 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], 'message: <code>where([{ \"a\": 1, \"b\": 2 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], { \"a\": 1, \"b\": 2 })</code> should return <code>[{ \"a\": 1, \"b\": 2 }, { \"a\": 1, \"b\": 2, \"c\": 2 }]</code>.');"
|
||||
=======
|
||||
"assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');",
|
||||
"assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], 'should return with multiples');",
|
||||
"assert.deepEqual(where([{ 'a': 1, 'b': 2 }, { 'a': 1 }, { 'a': 1, 'b': 2, 'c': 2 }], { 'a': 1, 'b': 2 }), [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2, 'c': 2 }], 'should return two objects in array');",
|
||||
"assert.deepEqual(where([{ 'a': 5 }, { 'b': 10 }, { 'a': 5, 'b': 10 }], { 'a': 5, 'b': 10 }), [{ 'a': 5, 'b': 10 }], 'should return a single object in array');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Global Object",
|
||||
@ -176,11 +201,19 @@
|
||||
"id": "a0b5010f579e69b815e7c5d6",
|
||||
"title": "Search and Replace",
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(myReplace(\"Let us go to the store\", \"store\", \"mall\"), \"Let us go to the mall\", 'message: <code>myReplace(\"Let us go to the store\", \"store\", \"mall\")</code> should return \"Let us go to the mall\".');",
|
||||
"assert.deepEqual(myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\"), \"He is Sitting on the couch\", 'message: <code>myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\")</code> should return \"He is Sitting on the couch\".');",
|
||||
"assert.deepEqual(myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", 'message: <code>myReplace(\"This has a spellngi error\", \"spellingi\", \"spelling\")</code> should return \"This has a spelling error\".');",
|
||||
"assert.deepEqual(myReplace(\"His name is Tom\", \"Tom\", \"john\"), \"His name is John\", 'message: <code>myReplace(\"His name is Tom\", \"Tom\", \"john\")</code> should return \"His name is John\".');",
|
||||
"assert.deepEqual(myReplace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\"), \"Let us get back to more Bonfires\", 'message: <code>myReplace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\")</code> should return \"Let us get back to more Bonfires\".');"
|
||||
=======
|
||||
"assert.deepEqual(replace(\"Let us go to the store\", \"store\", \"mall\"), \"Let us go to the mall\", '<code>replace(\"Let us go to the store\", \"store\", \"mall\")</code> should return \"Let us go to the mall\"');",
|
||||
"assert.deepEqual(replace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\"), \"He is Sitting on the couch\", '<code>replace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\")</code> should return \"He is Sitting on the couch\"');",
|
||||
"assert.deepEqual(replace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", '<code>replace(\"This has a spellngi error\", \"spellingi\", \"spelling\")</code> should return \"This has a spelling error\"');",
|
||||
"assert.deepEqual(replace(\"His name is Tom\", \"Tom\", \"john\"), \"His name is John\", '<code>replace(\"His name is Tom\", \"Tom\", \"john\")</code> should return \"His name is John\"');",
|
||||
"assert.deepEqual(replace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\"), \"Let us get back to more Bonfires\", '<code>replace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\")</code> should return \"Let us get back to more Bonfires\"');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"difficulty": "2.035",
|
||||
"description": [
|
||||
@ -220,11 +253,19 @@
|
||||
"id": "aa7697ea2477d1316795783b",
|
||||
"title": "Pig Latin",
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(translate(\"california\"), \"aliforniacay\", 'message: <code>translate(\"california\")</code> should return \"aliforniacay\".');",
|
||||
"assert.deepEqual(translate(\"paragraphs\"), \"aragraphspay\", 'message: <code>translate(\"paragraphs\")</code> should return \"aragraphspay\".');",
|
||||
"assert.deepEqual(translate(\"glove\"), \"oveglay\", 'message: <code>translate(\"glove\")</code> should return \"oveglay\".');",
|
||||
"assert.deepEqual(translate(\"algorithm\"), \"algorithmway\", 'message: <code>translate(\"algorithm\")</code> should return \"algorithmway\".');",
|
||||
"assert.deepEqual(translate(\"eight\"), \"eightway\", 'message: <code>translate(\"eight\")</code> should return \"eightway\".');"
|
||||
=======
|
||||
"assert.deepEqual(translate(\"california\"), \"aliforniacay\", '<code>translate(\"california\")</code> should return \"aliforniacay\"');",
|
||||
"assert.deepEqual(translate(\"paragraphs\"), \"aragraphspay\", '<code>translate(\"paragraphs\")</code> should return \"aragraphspay\"');",
|
||||
"assert.deepEqual(translate(\"glove\"), \"oveglay\", '<code>translate(\"glove\")</code> should return \"oveglay\"');",
|
||||
"assert.deepEqual(translate(\"algorithm\"), \"algorithmway\", '<code>translate(\"algorithm\")</code> should return \"algorithmway\"');",
|
||||
"assert.deepEqual(translate(\"eight\"), \"eightway\", '<code>translate(\"eight\")</code> should return \"eightway\"');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"difficulty": "2.04",
|
||||
"description": [
|
||||
@ -318,10 +359,17 @@
|
||||
"fearNotLetter(\"abce\");"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(fearNotLetter(\"abce\"), \"d\", 'message: <code>fearNotLetter(\"abce\")</code> should return \"d\".');",
|
||||
"assert.deepEqual(fearNotLetter(\"abcdefghjklmno\"), \"i\", 'message: <code>fearNotLetter(\"abcdefghjklmno\")</code> should return \"i\".');",
|
||||
"assert.isUndefined(fearNotLetter(\"bcd\"), 'message: <code>fearNotLetter(\"bcd\")</code> should return undefined.');",
|
||||
"assert.isUndefined(fearNotLetter(\"yz\"), 'message: <code>fearNotLetter(\"yz\")</code> should return undefined.');"
|
||||
=======
|
||||
"assert.deepEqual(fearNotLetter(\"abce\"), \"d\", '<code>fearNotLetter(\"abce\")</code> should return d');",
|
||||
"assert.deepEqual(fearNotLetter(\"abcdefghjklmno\"), \"i\", '<code>fearNotLetter(\"abcdefghjklmno\")</code> should return i');",
|
||||
"assert.isUndefined(fearNotLetter(\"bcd\"), '<code>fearNotLetter(\"bcd\")</code> should return undefined');",
|
||||
"assert.isUndefined(fearNotLetter(\"yz\"), '<code>fearNotLetter(\"yz\")</code> should return undefined');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"String.charCodeAt()",
|
||||
@ -524,12 +572,21 @@
|
||||
"sumFibs(4);"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert(typeof(sumFibs(1)) === \"number\", 'message: <code>sumFibs()</code> should return a number.');",
|
||||
"assert.deepEqual(sumFibs(1000), 1785, 'message: <code>sumFibs(1000)</code> should return 1785.');",
|
||||
"assert.deepEqual(sumFibs(4000000), 4613732, 'message: <code>sumFibs(4000000)</code> should return 4613732.');",
|
||||
"assert.deepEqual(sumFibs(4), 5, 'message: <code>sumFibs(4)</code> should return 5.');",
|
||||
"assert.deepEqual(sumFibs(75024), 60696, 'message: <code>sumFibs(75024)</code> should return 60696.');",
|
||||
"assert.deepEqual(sumFibs(75025), 135721, 'message: <code>sumFibs(75025)</code> should return 135721.');"
|
||||
=======
|
||||
"assert.deepEqual(typeof(sumFibs(1)), \"number\", \"The result should be a number\");",
|
||||
"assert.deepEqual(sumFibs(1000), 1785, '<code>sumFibs(1000)</code> should return 1785');",
|
||||
"assert.deepEqual(sumFibs(4000000), 4613732, '<code>sumFibs(4000000)</code> should return 4613732');",
|
||||
"assert.deepEqual(sumFibs(4), 5, '<code>sumFibs(4)</code> should return 5');",
|
||||
"assert.deepEqual(sumFibs(75024), 60696, '<code>sumFibs(75024)</code> should return 60696');",
|
||||
"assert.deepEqual(sumFibs(75025), 135721, '<code>sumFibs(75025)</code> should return 135721');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Remainder"
|
||||
@ -565,9 +622,15 @@
|
||||
"sumPrimes(10);"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(typeof(sumPrimes(10)), \"number\", 'message: <code>sumPrimes()</code> should return a number.');",
|
||||
"assert.deepEqual(sumPrimes(10), 17, 'message: <code>sumPrimes(10)</code> should return 17.');",
|
||||
"assert.deepEqual(sumPrimes(977), 73156, 'message: <code>sumPrimes(977)</code> should return 73156.');"
|
||||
=======
|
||||
"assert.deepEqual(typeof(sumPrimes(10)), \"number\", \"The result should be a number\");",
|
||||
"assert.deepEqual(sumPrimes(10), 17, '<code>sumPrimes(10)</code> should return 17');",
|
||||
"assert.deepEqual(sumPrimes(977), 73156, '<code>sumPrimes(977)</code> should return 73156');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"For Loops",
|
||||
@ -605,10 +668,17 @@
|
||||
"smallestCommons([1,5]);"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(typeof(smallestCommons([1, 5])), \"number\", 'message: <code>smallestCommons()</code> should return a number.');",
|
||||
"assert.deepEqual(smallestCommons([1, 5]), 60, 'message: <code>smallestCommons([1, 5])</code> should return 60.');",
|
||||
"assert.deepEqual(smallestCommons([5, 1]), 60, 'message: <code>smallestCommons([5, 1])</code> should return 60.');",
|
||||
"assert.deepEqual(smallestCommons([1, 13]), 360360, 'message: <code>smallestCommons([1, 13])</code> should return 360360.');"
|
||||
=======
|
||||
"assert.deepEqual(typeof(smallestCommons([1, 5])), \"number\", \"The result should be a number\");",
|
||||
"assert.deepEqual(smallestCommons([1, 5]), 60, '<code>smallestCommons([1, 5])</code> should return 60');",
|
||||
"assert.deepEqual(smallestCommons([5, 1]), 60, '<code>smallestCommons([5, 1])</code> should return 60');",
|
||||
"assert.deepEqual(smallestCommons([1, 13]), 360360, '<code>smallestCommons([1, 13])</code> should return 360360');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Smallest Common Multiple"
|
||||
@ -679,10 +749,17 @@
|
||||
"drop([1, 2, 3], function(n) {return n < 3; });"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"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, 4], function(n) {return n>= 3;}), [3, 4], '<code>drop([1, 2, 3, 4], function(n) {return n>= 3;})</code> should return [3, 4]');",
|
||||
"assert.deepEqual(drop([1, 2, 3], function(n) {return n > 0; }), [1, 2, 3], '<code>drop([1, 2, 3], function(n) {return n > 0; })</code> should return [1, 2, 3]');",
|
||||
"assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n > 5;}), [], '<code>drop([1, 2, 3, 4], function(n) {return n > 5;})</code> should return []');",
|
||||
"assert.deepEqual(drop([1, 2, 3, 7, 4], function(n) {return n > 3}), [7, 4], '<code>drop([1, 2, 3, 7, 4], function(n) {return n>= 3})</code> should return [7, 4]');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Arguments object",
|
||||
@ -756,8 +833,13 @@
|
||||
"binaryAgent(\"01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111\");"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(binaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111'), \"Aren't bonfires fun!?\", 'message: <code>binaryAgent(\"01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111\")</code> should return \"Aren't bonfires fun!?\"');",
|
||||
"assert.deepEqual(binaryAgent(\"01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001\"), \"I love FreeCodeCamp!\", 'message: <code>binaryAgent(\"01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001\"</code> should return \"I love FreeCodeCamp!\"');"
|
||||
=======
|
||||
"assert.deepEqual(binaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111'), \"Aren't bonfires fun!?\", \"<code>binaryAgent()</code> should return Aren't bonfires fun!?\");",
|
||||
"assert.deepEqual(binaryAgent('01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001'), \"I love FreeCodeCamp!\", '<code>binaryAgent()</code> should return \"I love FreeCodeCamp!\"');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"String.charCodeAt()",
|
||||
@ -837,11 +919,19 @@
|
||||
"add(2,3);"
|
||||
],
|
||||
"tests": [
|
||||
<<<<<<< HEAD
|
||||
"assert.deepEqual(add(2, 3), 5, 'message: <code>add(2, 3)</code> should return 5.');",
|
||||
"assert.deepEqual(add(2)(3), 5, 'message: <code>add(2)(3)</code> should return 5.');",
|
||||
"assert.isUndefined(add(\"http://bit.ly/IqT6zt\"), 'message: <code>add(\"http://bit.ly/IqT6zt\")</code> should return undefined.');",
|
||||
"assert.isUndefined(add(2, \"3\"), 'message: <code>add(2, \"3\")</code> should return undefined.');",
|
||||
"assert.isUndefined(add(2)([3]), 'message: <code>add(2)([3])</code> should return undefined.');"
|
||||
=======
|
||||
"assert.deepEqual(add(2, 3), 5, '<code>add(2, 3)</code> should return 5');",
|
||||
"assert.deepEqual(add(2)(3), 5, '<code>add(2)(3)</code> should return 5');",
|
||||
"assert.isUndefined(add(\"http://bit.ly/IqT6zt\"), '<code>add(\"http://bit.ly/IqT6zt\")</code> should return undefined');",
|
||||
"assert.isUndefined(add(2, \"3\"), '<code>add(2, \"3\")</code> should return undefined');",
|
||||
"assert.isUndefined(add(2)([3]), '<code>add(2)([3])</code> should return undefined');"
|
||||
>>>>>>> staging
|
||||
],
|
||||
"MDNlinks": [
|
||||
"Global Function Object",
|
||||
|
@ -37,7 +37,7 @@
|
||||
},
|
||||
{
|
||||
"id": "bd7158d8c442eddfaeb5bd19",
|
||||
"title": "Wikipedia Viewer",
|
||||
"title": "Build a Wikipedia Viewer",
|
||||
"difficulty": 1.03,
|
||||
"challengeSeed": ["126415131"],
|
||||
"description": [
|
||||
|
@ -791,6 +791,7 @@
|
||||
"description": [
|
||||
"You can also target all the even-numbered elements.",
|
||||
"Here's how you would target all the odd-numbered elements with class <code>target</code> and give them classes: <code>$(\".target:odd\").addClass(\"animated shake\");</code>",
|
||||
"Note that jQuery is zero-indexed, meaning that, counter-intuitively, <code>:odd</code> selects the second element, fourth element, and so on.",
|
||||
"Try selecting all the even-numbered elements - that is, what your browser will consider even-numbered elements - and giving them the classes of <code>animated</code> and <code>shake</code>."
|
||||
],
|
||||
"tests": [
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
import { RoutingContext } from 'react-router';
|
||||
import Fetchr from 'fetchr';
|
||||
import Location from 'react-router/lib/Location';
|
||||
import { createLocation } from 'history';
|
||||
import debugFactory from 'debug';
|
||||
import { app$ } from '../../common/app';
|
||||
import { RenderToString } from 'thundercats-react';
|
||||
@ -30,25 +30,25 @@ export default function reactSubRouter(app) {
|
||||
|
||||
function serveReactApp(req, res, next) {
|
||||
const services = new Fetchr({ req });
|
||||
const location = new Location(req.path, req.query);
|
||||
const location = createLocation(req.path);
|
||||
|
||||
// returns a router wrapped app
|
||||
app$(location)
|
||||
app$({ location })
|
||||
// if react-router does not find a route send down the chain
|
||||
.filter(function({ initialState }) {
|
||||
if (!initialState) {
|
||||
.filter(function({ props}) {
|
||||
if (!props) {
|
||||
debug('react tried to find %s but got 404', location.pathname);
|
||||
return next();
|
||||
}
|
||||
return !!initialState;
|
||||
return !!props;
|
||||
})
|
||||
.flatMap(function({ initialState, AppCat }) {
|
||||
.flatMap(function({ props, AppCat }) {
|
||||
// call thundercats renderToString
|
||||
// prefetches data and sets up it up for current state
|
||||
debug('rendering to string');
|
||||
return RenderToString(
|
||||
AppCat(null, services),
|
||||
React.createElement(Router, initialState)
|
||||
React.createElement(RoutingContext, props)
|
||||
);
|
||||
})
|
||||
// makes sure we only get one onNext and closes subscription
|
||||
|
@ -471,6 +471,7 @@ module.exports = function(app) {
|
||||
}
|
||||
|
||||
function challengeMap({ user = {} }, res, next) {
|
||||
let lastCompleted;
|
||||
const daysRunning = moment().diff(new Date('10/15/2014'), 'days');
|
||||
|
||||
// if user
|
||||
@ -513,7 +514,13 @@ module.exports = function(app) {
|
||||
})
|
||||
.filter(({ name }) => name !== 'Hikes')
|
||||
// turn stream of blocks into a stream of an array
|
||||
.toArray();
|
||||
.toArray()
|
||||
.doOnNext((blocks) => {
|
||||
const lastCompletedBlock = _.findLast(blocks, (block) => {
|
||||
return block.completed === 100;
|
||||
});
|
||||
lastCompleted = lastCompletedBlock.name;
|
||||
});
|
||||
|
||||
Observable.combineLatest(
|
||||
camperCount$,
|
||||
@ -526,6 +533,7 @@ module.exports = function(app) {
|
||||
blocks,
|
||||
daysRunning,
|
||||
camperCount,
|
||||
lastCompleted,
|
||||
title: "A map of all Free Code Camp's Challenges"
|
||||
});
|
||||
},
|
||||
|
@ -170,7 +170,6 @@ module.exports = function(app) {
|
||||
title: story.headline,
|
||||
link: story.link,
|
||||
originalStoryLink: dashedName,
|
||||
originalStoryAuthorEmail: story.author.email || '',
|
||||
author: story.author,
|
||||
rank: story.upVotes.length,
|
||||
upVotes: story.upVotes,
|
||||
@ -373,13 +372,11 @@ module.exports = function(app) {
|
||||
author: {
|
||||
picture: req.user.picture,
|
||||
userId: req.user.id,
|
||||
username: req.user.username,
|
||||
email: req.user.email
|
||||
username: req.user.username
|
||||
},
|
||||
image: data.image,
|
||||
storyLink: storyLink,
|
||||
metaDescription: data.storyMetaDescription,
|
||||
originalStoryAuthorEmail: req.user.email
|
||||
metaDescription: data.storyMetaDescription
|
||||
});
|
||||
return saveInstance(newStory);
|
||||
});
|
||||
|
@ -76,6 +76,8 @@ module.exports = function(app) {
|
||||
);
|
||||
router.get('/account/unlink/:provider', getOauthUnlink);
|
||||
router.get('/account', getAccount);
|
||||
router.get('/vote1', vote1);
|
||||
router.get('/vote2', vote2);
|
||||
// Ensure this is the last route!
|
||||
router.get('/:username', returnUser);
|
||||
|
||||
@ -332,4 +334,36 @@ module.exports = function(app) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function vote1(req, res) {
|
||||
if (req.user) {
|
||||
req.user.tshirtVote = 1;
|
||||
req.user.save(function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
req.flash('success', {msg: 'Thanks for voting!'});
|
||||
res.redirect('/map');
|
||||
});
|
||||
} else {
|
||||
req.flash('error', {msg: 'You must be signed in to vote.'});
|
||||
res.redirect('/map');
|
||||
}
|
||||
}
|
||||
|
||||
function vote2(req, res) {
|
||||
if (req.user) {
|
||||
req.user.tshirtVote = 2;
|
||||
req.user.save(function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
req.flash('success', {msg: 'Thanks for voting!'});
|
||||
res.redirect('/map');
|
||||
});
|
||||
} else {
|
||||
req.flash('error', {msg: 'You must be signed in to vote.'});
|
||||
res.redirect('/map');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -26,13 +26,12 @@ export default function addReturnToUrl() {
|
||||
return function(req, res, next) {
|
||||
// Remember original destination before login.
|
||||
var path = req.path.split('/')[1];
|
||||
var subPath = req.path.split('/')[2];
|
||||
|
||||
if (
|
||||
req.method !== 'GET' ||
|
||||
pathsOfNoReturnRegex.test(path) ||
|
||||
!whiteListRegex.test(path) ||
|
||||
(/news/i).test(path) && (/hot/i).test(subPath)
|
||||
(/news/i).test(path) && (/hot/i).test(req.path)
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
|
@ -17,7 +17,36 @@ block content
|
||||
| since we launched  
|
||||
span.text-primary #{daysRunning}  
|
||||
| days ago.
|
||||
a.btn.btn-lg.signup-btn.btn-block(href="https://www.facebook.com/sharer/sharer.php?u=http://freecodecamp.com" target='_blank') Share our open source community on Facebook and help us grow.
|
||||
.spacer
|
||||
if (user && !user.tshirtVote && user.progressTimestamps.length > 5)
|
||||
h3.text-center Vote for the T-shirt design you like the most.
|
||||
h4.text-center We'll announce the winning design during our Summit on Saturday at Noon EST on 
|
||||
a(href='https://twitch.tv/freecodecamp' target='_blank') Twitch.tv
|
||||
|  and it will become our community's first official t-shirt (in women's and men's sizes).
|
||||
.row
|
||||
.col-xs-6
|
||||
a(href="http://i.imgur.com/LlXGa5y.png" data-lightbox="img-enlarge")
|
||||
img.img-responsive(src='http://i.imgur.com/LlXGa5y.png' alt="t-shirt option 1 women's")
|
||||
.col-xs-6
|
||||
a(href="http://i.imgur.com/aefwnnv.png" data-lightbox="img-enlarge")
|
||||
img.img-responsive(src='http://i.imgur.com/aefwnnv.png' alt="t-shirt option 2 women's")
|
||||
.button-spacer
|
||||
.row
|
||||
.col-xs-6
|
||||
a(href="http://i.imgur.com/aYH0aqf.png" data-lightbox="img-enlarge")
|
||||
img.img-responsive(src='http://i.imgur.com/aYH0aqf.png' alt="t-shirt option 1 men's")
|
||||
.col-xs-6
|
||||
a(href="http://i.imgur.com/v9KlV4g.png" data-lightbox="img-enlarge")
|
||||
img.img-responsive(src='http://i.imgur.com/v9KlV4g.png' alt="t-shirt option 2 men's")
|
||||
.button-spacer
|
||||
.row
|
||||
.col-xs-6
|
||||
h3.text-center "Minified JavaScript Logo"
|
||||
a.button.btn.btn-block.btn-primary(href='/vote1') Vote for this Design
|
||||
.col-xs-6
|
||||
h3.text-center "Function Call Logo"
|
||||
a.button.btn.btn-block.btn-primary(href='/vote2') Vote for this design
|
||||
.spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2
|
||||
h3 800 Hours of Practice:
|
||||
@ -102,7 +131,16 @@ block content
|
||||
span= challenge.title
|
||||
span.sr-only= " Incomplete"
|
||||
|
||||
//#announcementModal.modal(tabindex='-1')
|
||||
if (challengeBlock.completed === 100)
|
||||
.button-spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-md-6.col-sm-offset-3.col-md-offset-2.hidden
|
||||
a.btn.btn-lg.btn-block.signup-btn.map-challenge-block-share Section complete. Share your Portfolio with your friends.
|
||||
.hidden(id="#{challengeBlock.name}")
|
||||
script.
|
||||
var username = !{JSON.stringify(user && user.username || '')};
|
||||
var lastCompleted = !{JSON.stringify(lastCompleted || false)}
|
||||
// #announcementModal.modal(tabindex='-1')
|
||||
// .modal-dialog.animated.fadeInUp.fast-animation
|
||||
// .modal-content
|
||||
// .modal-header.challenge-list-header Add us to your LinkedIn profile
|
||||
|
@ -55,9 +55,6 @@ block content
|
||||
label.btn.btn-success#trigger-help-modal
|
||||
i.fa.fa-medkit
|
||||
| Help
|
||||
label.btn.btn-success#trigger-pair-modal
|
||||
i.fa.fa-user-plus
|
||||
| Pair
|
||||
label.btn.btn-success#trigger-issue-modal
|
||||
i.fa.fa-bug
|
||||
| Bug
|
||||
|
@ -94,10 +94,6 @@ 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)
|
||||
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")
|
||||
i.fa.fa-twitter  
|
||||
= phrase
|
||||
else
|
||||
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) Go to my next challenge
|
||||
include ../partials/challenge-modals
|
||||
|
@ -69,12 +69,6 @@ block content
|
||||
a.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf) I've completed this challenge (ctrl + enter)
|
||||
script.
|
||||
$('#complete-courseware-editorless-dialog').bind('keypress', modalControlEnterHandler);
|
||||
|
||||
if (user.progressTimestamps.length > 2)
|
||||
.button-spacer
|
||||
a.btn.btn-lg.btn-block.btn-twitter(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" target="_blank")
|
||||
i.fa.fa-twitter  
|
||||
= phrase
|
||||
else
|
||||
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) I've completed this challenge (ctrl + enter)
|
||||
script.
|
||||
|
@ -27,9 +27,6 @@ block content
|
||||
.btn.btn-success.btn-big#trigger-help-modal
|
||||
i.fa.fa-medkit
|
||||
| Help
|
||||
.btn.btn-success.btn-big#trigger-pair-modal
|
||||
i.fa.fa-user-plus
|
||||
| Pair
|
||||
.btn.btn-success.btn-big#trigger-issue-modal
|
||||
i.fa.fa-bug
|
||||
| Bug
|
||||
|
@ -1,17 +1,3 @@
|
||||
#pair-modal.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeIn.fast-animation
|
||||
.modal-content
|
||||
.modal-header.challenge-list-header Ready to pair program?
|
||||
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
|
||||
.modal-body.text-center
|
||||
h3 This will take you to our pair programming room where you can request a pair.
|
||||
h3 You'll need  
|
||||
a(href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-install-Screenhero' target='_blank') Screenhero
|
||||
| .
|
||||
h3 Other campers may then message you about pair programming.
|
||||
a.btn.btn-lg.btn-primary.btn-block.close-modal(href='https://gitter.im/FreeCodeCamp/LetsPair', target='_blank') Take me to the pair programming room
|
||||
a.btn.btn-lg.btn-info.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Cancel
|
||||
|
||||
#issue-modal.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeIn.fast-animation
|
||||
.modal-content
|
||||
|
@ -65,7 +65,7 @@ block content
|
||||
|
||||
.big-spacer
|
||||
.thumbnail
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/EZHzKCV.gif' alt='A gif showing you how to click the link below to go to our chat room and click the \"sign in with GitHub\" button. Then you can click into the text input field and type a message to your fellow campers.')
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/Uuc2Ked.gif' alt='A gif showing you how to click the link below to go to our chat room and click the \"sign in with GitHub\" button. Then you can click into the text input field and type a message to your fellow campers.')
|
||||
.caption
|
||||
p.large-p Try this: 
|
||||
| Now that you have a GitHub account, you can 
|
||||
@ -99,12 +99,6 @@ block content
|
||||
a(href='https://gitter.im/apps' target='_blank') download the chat room app
|
||||
|  to your computer or phone.
|
||||
|
||||
.big-spacer
|
||||
.thumbnail
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/DoOqkNW.gif' alt='A gif showing how you can click the "Wiki" button in your upper-right corner to access the wiki.')
|
||||
.caption
|
||||
p.large-p Try this: Click the "Wiki" button in your upper right hand corner. Our community has contributed lots of useful information to this searchable wiki.
|
||||
|
||||
.big-spacer
|
||||
.thumbnail
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/FkEzbto.gif' alt='A gif showing how you can click your profile image in your upper right hand corner to access the account page and connect GitHub.')
|
||||
@ -128,25 +122,15 @@ block content
|
||||
.thumbnail
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/Elb3dfj.jpg' alt='A picture of some of our campers meeting in a local cafe. 3 men and 3 women are sitting around a table with laptops out, and are smiling and coding.')
|
||||
.caption
|
||||
p.large-p Our Campsites help you code with campers in your city. You can coordinate study groups or attend local coding events together.
|
||||
p.large-p Our Campsites help you code with campers in your city. You can discuss coding and attend local Coffee-n-Code events.
|
||||
|
||||
.big-spacer
|
||||
.thumbnail
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/EZHzKCV.gif' alt="A gif showing how you can click the link below, find your city on the list of Campsites, then click on the Facebook link for your city and join your city's Facebook group.")
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/tYf8jrI.gif' alt="A gif showing how you can click the link below, find your city on the list of Campsites, then click on the Facebook link for your city and join your city's Facebook group.")
|
||||
.caption
|
||||
p.large-p Try this: 
|
||||
a(href='https://github.com/FreeCodeCamp/freecodecamp/wiki/List-of-Free-Code-Camp-city-based-Campsites' target='_blank') Find your city on this list
|
||||
| . Click the "Join group" button to join your city's Facebook group. If your city isn't on this list, 
|
||||
a(href='https://github.com/FreeCodeCamp/freecodecamp/wiki/How-to-create-a-Campsite-for-your-city' target='_blank') follow these directions to create a Facebook group for your city
|
||||
| .
|
||||
|
||||
.big-spacer
|
||||
.thumbnail
|
||||
img.gif-block.img-center.img-responsive(src='http://i.imgur.com/3AgvJQg.gif' alt="A gif showing how click the link below, find your city, and click the \"Gitter\" button to join your city's Gitter chat room")
|
||||
.caption
|
||||
p.large-p Try this: 
|
||||
a(href='https://github.com/FreeCodeCamp/freecodecamp/wiki/List-of-Free-Code-Camp-city-based-Campsites' target='_blank') Go back to our list of Campsites 
|
||||
| and click "Gitter" to join your city's chat room.
|
||||
| , then click it. Click the "Join group" button to join your city's Campsite.
|
||||
|
||||
.big-spacer
|
||||
.thumbnail
|
||||
|
@ -1,7 +1,6 @@
|
||||
script.
|
||||
var storyId = !{JSON.stringify(id)};
|
||||
var originalStoryLink = !{JSON.stringify(originalStoryLink)};
|
||||
var originalStoryAuthorEmail = !{JSON.stringify(originalStoryAuthorEmail)};
|
||||
var upVotes = !{JSON.stringify(upVotes)};
|
||||
var image = !{JSON.stringify(image)};
|
||||
var hasUserVoted = !{JSON.stringify(hasUserVoted)};
|
||||
|
Reference in New Issue
Block a user