feat: use eslint with prettier to format code
This commit is contained in:
parent
be36915605
commit
fc8c71ad16
@ -25,7 +25,7 @@ export default function addReturnToUrl() {
|
||||
req.method !== 'GET' ||
|
||||
pathsOfNoReturnRegex.test(path) ||
|
||||
!whiteListRegex.test(path) ||
|
||||
(/hot/i).test(req.path)
|
||||
/hot/i.test(req.path)
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export default function() {
|
||||
});
|
||||
return function csrf(req, res, next) {
|
||||
const path = req.path.split('/')[1];
|
||||
if ((/(^api$|^unauthenticated$|^internal$|^p$)/).test(path)) {
|
||||
if (/(^api$|^unauthenticated$|^internal$|^p$)/.test(path)) {
|
||||
return next();
|
||||
}
|
||||
return protection(req, res, next);
|
||||
|
@ -17,7 +17,7 @@ const getFirstChallenge = _.once(_getFirstChallenge);
|
||||
* interface ChallengeMap {
|
||||
* result: {
|
||||
* superBlocks: [ ...superBlockDashedName: String ]
|
||||
* },
|
||||
* },
|
||||
* entities: {
|
||||
* superBlock: {
|
||||
* [ ...superBlockDashedName ]: SuperBlock
|
||||
@ -49,10 +49,12 @@ export function _cachedMap({ Block, Challenge }) {
|
||||
});
|
||||
const blockMap = Observable.combineLatest(
|
||||
blocks.map(blocks =>
|
||||
blocks.map(block => block.toJSON()).reduce((hash, block) => {
|
||||
hash[block.dashedName] = block;
|
||||
return hash;
|
||||
}, {})
|
||||
blocks
|
||||
.map(block => block.toJSON())
|
||||
.reduce((hash, block) => {
|
||||
hash[block.dashedName] = block;
|
||||
return hash;
|
||||
}, {})
|
||||
),
|
||||
challenges
|
||||
).map(([blocksMap, challenges]) => {
|
||||
|
@ -35,14 +35,14 @@ export const wrapPageElement = ({ element, props }) => {
|
||||
</DefaultLayout>
|
||||
);
|
||||
}
|
||||
if ((/^\/guide(\/.*)*/).test(pathname)) {
|
||||
if (/^\/guide(\/.*)*/.test(pathname)) {
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<GuideLayout>{element}</GuideLayout>
|
||||
</DefaultLayout>
|
||||
);
|
||||
}
|
||||
if ((/^\/learn(\/.*)*/).test(pathname)) {
|
||||
if (/^\/learn(\/.*)*/.test(pathname)) {
|
||||
return <DefaultLayout showFooter={false}>{element}</DefaultLayout>;
|
||||
}
|
||||
return <DefaultLayout>{element}</DefaultLayout>;
|
||||
|
@ -148,8 +148,8 @@ exports.onCreateWebpackConfig = ({ stage, rules, plugins, actions }) => {
|
||||
/* eslint-disable max-len */
|
||||
exclude: modulePath => {
|
||||
return (
|
||||
(/node_modules/).test(modulePath) &&
|
||||
!(/(ansi-styles|chalk|strict-uri-encode|react-freecodecamp-search)/).test(
|
||||
/node_modules/.test(modulePath) &&
|
||||
!/(ansi-styles|chalk|strict-uri-encode|react-freecodecamp-search)/.test(
|
||||
modulePath
|
||||
)
|
||||
);
|
||||
|
@ -35,14 +35,14 @@ export const wrapPageElement = ({ element, props }) => {
|
||||
</DefaultLayout>
|
||||
);
|
||||
}
|
||||
if ((/^\/guide(\/.*)*/).test(pathname)) {
|
||||
if (/^\/guide(\/.*)*/.test(pathname)) {
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<GuideLayout>{element}</GuideLayout>
|
||||
</DefaultLayout>
|
||||
);
|
||||
}
|
||||
if ((/^\/learn(\/.*)*/).test(pathname)) {
|
||||
if (/^\/learn(\/.*)*/.test(pathname)) {
|
||||
return <DefaultLayout showFooter={false}>{element}</DefaultLayout>;
|
||||
}
|
||||
return <DefaultLayout>{element}</DefaultLayout>;
|
||||
|
@ -31,28 +31,26 @@ exports.sourceNodes = function sourceChallengesSourceNodes(
|
||||
persistent: true
|
||||
});
|
||||
|
||||
watcher.on('ready', sourceAndCreateNodes).on(
|
||||
'change',
|
||||
filePath =>
|
||||
(/\.md$/).test(filePath)
|
||||
? onSourceChange(filePath)
|
||||
.then(challenge => {
|
||||
reporter.info(
|
||||
`File changed at ${filePath}, replacing challengeNode id ${
|
||||
challenge.id
|
||||
}`
|
||||
);
|
||||
return createChallengeNode(challenge, reporter);
|
||||
})
|
||||
.then(createNode)
|
||||
.catch(e =>
|
||||
reporter.error(`fcc-replace-challenge
|
||||
watcher.on('ready', sourceAndCreateNodes).on('change', filePath =>
|
||||
/\.md$/.test(filePath)
|
||||
? onSourceChange(filePath)
|
||||
.then(challenge => {
|
||||
reporter.info(
|
||||
`File changed at ${filePath}, replacing challengeNode id ${
|
||||
challenge.id
|
||||
}`
|
||||
);
|
||||
return createChallengeNode(challenge, reporter);
|
||||
})
|
||||
.then(createNode)
|
||||
.catch(e =>
|
||||
reporter.error(`fcc-replace-challenge
|
||||
|
||||
${e.message}
|
||||
|
||||
`)
|
||||
)
|
||||
: null
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
||||
function sourceAndCreateNodes() {
|
||||
|
@ -20,10 +20,7 @@ function markdownToHTML(node) {
|
||||
}
|
||||
|
||||
module.exports = function forumEmojiPlugin({ markdownAST }) {
|
||||
visit(
|
||||
markdownAST,
|
||||
'image',
|
||||
imageNode =>
|
||||
emojiRE.test(imageNode.title) ? markdownToHTML(imageNode) : imageNode
|
||||
visit(markdownAST, 'image', imageNode =>
|
||||
emojiRE.test(imageNode.title) ? markdownToHTML(imageNode) : imageNode
|
||||
);
|
||||
};
|
||||
|
@ -191,7 +191,7 @@ function ShowSettings(props) {
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
href={`/${username}`}
|
||||
>
|
||||
>
|
||||
Show me my public portfolio
|
||||
</Button>
|
||||
<Button
|
||||
@ -201,7 +201,7 @@ function ShowSettings(props) {
|
||||
className='btn-invert'
|
||||
href={'/signout'}
|
||||
onClick={createHandleSignoutClick(hardGoTo)}
|
||||
>
|
||||
>
|
||||
Sign me out of freeCodeCamp
|
||||
</Button>
|
||||
</FullWidthRow>
|
||||
|
@ -33,7 +33,7 @@ function ShowUnsubscribed({ unsubscribeId }) {
|
||||
bsSize='lg'
|
||||
bsStyle='primary'
|
||||
href={`${apiLocation}/internal/resubscribe/${unsubscribeId}`}
|
||||
>
|
||||
>
|
||||
You can click here to resubscribe
|
||||
</Button>
|
||||
</FullWidthRow>
|
||||
|
@ -18,8 +18,8 @@ function DonateCompletion({ processing, reset, success, error = null }) {
|
||||
const heading = processing
|
||||
? 'We are processing your donation.'
|
||||
: success
|
||||
? 'Your donation was successful.'
|
||||
: 'Something went wrong with your donation';
|
||||
? 'Your donation was successful.'
|
||||
: 'Something went wrong with your donation';
|
||||
return (
|
||||
<Alert bsStyle={style} className='donation-completion'>
|
||||
<h4>{heading}</h4>
|
||||
|
@ -184,7 +184,7 @@ class DonateForm extends Component {
|
||||
disabled={!isFormValid}
|
||||
id='confirm-donation-btn'
|
||||
type='submit'
|
||||
>
|
||||
>
|
||||
Confirm your donation of $5 / month
|
||||
</Button>
|
||||
<Spacer />
|
||||
|
@ -20,9 +20,12 @@ import DonateText from './DonateText';
|
||||
|
||||
import '../Donation.css';
|
||||
|
||||
const mapStateToProps = createSelector(isDonationModalOpenSelector, show => ({
|
||||
show
|
||||
}));
|
||||
const mapStateToProps = createSelector(
|
||||
isDonationModalOpenSelector,
|
||||
show => ({
|
||||
show
|
||||
})
|
||||
);
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
|
@ -15,7 +15,7 @@ function Flash({ messages, onClose }) {
|
||||
className='flash-message'
|
||||
key={id}
|
||||
onDismiss={createDismissHandler(onClose, id)}
|
||||
>
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: message }} />
|
||||
</Alert>
|
||||
));
|
||||
|
@ -19,7 +19,7 @@ const ColHeader = ({ children, ...other }) => (
|
||||
ColHeader.propTypes = propTypes;
|
||||
|
||||
const Link = ({ children, to, external, ...other }) => {
|
||||
if (!external && (/^\/(?!\/)/).test(to)) {
|
||||
if (!external && /^\/(?!\/)/.test(to)) {
|
||||
return (
|
||||
<GatsbyLink to={to} {...other}>
|
||||
{children}
|
||||
|
@ -12,9 +12,12 @@ import { gtagReportConversion } from '../../../analytics/gtag';
|
||||
|
||||
import './login.css';
|
||||
|
||||
const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({
|
||||
isSignedIn
|
||||
}));
|
||||
const mapStateToProps = createSelector(
|
||||
isSignedInSelector,
|
||||
isSignedIn => ({
|
||||
isSignedIn
|
||||
})
|
||||
);
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
navigate: location => dispatch(hardGoTo(location))
|
||||
});
|
||||
@ -38,7 +41,7 @@ function Login(props) {
|
||||
className={
|
||||
(restProps.block ? 'btn-cta-big' : '') + ' signup-btn btn-cta'
|
||||
}
|
||||
>
|
||||
>
|
||||
{children || 'Sign In'}
|
||||
</Button>
|
||||
</a>
|
||||
|
@ -6,9 +6,12 @@ import { createSelector } from 'reselect';
|
||||
|
||||
import { userSelector } from '../../../redux';
|
||||
|
||||
const mapStateToProps = createSelector(userSelector, ({ picture }) => ({
|
||||
picture
|
||||
}));
|
||||
const mapStateToProps = createSelector(
|
||||
userSelector,
|
||||
({ picture }) => ({
|
||||
picture
|
||||
})
|
||||
);
|
||||
|
||||
function SignedIn({ picture }) {
|
||||
return (
|
||||
|
@ -78,7 +78,7 @@ class Header extends Component {
|
||||
className='menu-button'
|
||||
onClick={this.toggleClass}
|
||||
ref={this.menuButtonRef}
|
||||
>
|
||||
>
|
||||
Menu
|
||||
</span>
|
||||
<Media onChange={this.handleMediaChange} query='(max-width: 734px)' />
|
||||
|
@ -93,14 +93,14 @@ export class Block extends Component {
|
||||
<li
|
||||
className={'map-challenge-title' + completedClass}
|
||||
key={'map-challenge' + challenge.fields.slug}
|
||||
>
|
||||
>
|
||||
<span className='badge map-badge'>
|
||||
{i !== 0 && this.renderCheckMark(challenge.isCompleted)}
|
||||
</span>
|
||||
<Link
|
||||
onClick={this.handleChallengeClick(challenge.fields.slug)}
|
||||
to={challenge.fields.slug}
|
||||
>
|
||||
>
|
||||
{challenge.title || challenge.frontmatter.title}
|
||||
</Link>
|
||||
</li>
|
||||
|
@ -14,9 +14,10 @@ import { ChallengeNode } from '../../../redux/propTypes';
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const expandedSelector = makeExpandedSuperBlockSelector(ownProps.superBlock);
|
||||
|
||||
return createSelector(expandedSelector, isExpanded => ({ isExpanded }))(
|
||||
state
|
||||
);
|
||||
return createSelector(
|
||||
expandedSelector,
|
||||
isExpanded => ({ isExpanded })
|
||||
)(state);
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
|
@ -75,7 +75,7 @@ function Supporters({ isDonating, activeDonations }) {
|
||||
bsStyle='primary'
|
||||
href='https://donate.freecodecamp.org'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Click here to become a Supporter
|
||||
</Button>
|
||||
</FullWidthRow>
|
||||
|
@ -50,7 +50,7 @@ export function DynamicForm({
|
||||
id={`dynamic-${id}`}
|
||||
onSubmit={handleSubmit(submit)}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
>
|
||||
<FormFields errors={errors} fields={fields} options={options} />
|
||||
<BlockSaveWrapper>
|
||||
{hideButton ? null : (
|
||||
@ -59,7 +59,7 @@ export function DynamicForm({
|
||||
(allPristine && !enableSubmit) ||
|
||||
!!Object.keys(errors).filter(key => errors[key]).length
|
||||
}
|
||||
>
|
||||
>
|
||||
{buttonText ? buttonText : null}
|
||||
</BlockSaveButton>
|
||||
)}
|
||||
|
@ -65,7 +65,7 @@ export function getValidationState(field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((/https?:\/\/glitch\.com\/edit\/#!\/.*/g).test(field.value)) {
|
||||
if (/https?:\/\/glitch\.com\/edit\/#!\/.*/g.test(field.value)) {
|
||||
return 'glitch-warning';
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ export default function ToggleButton({
|
||||
disabled={value}
|
||||
type='radio'
|
||||
value={1}
|
||||
>
|
||||
>
|
||||
{onLabel}
|
||||
</TB>
|
||||
<TB
|
||||
@ -46,7 +46,7 @@ export default function ToggleButton({
|
||||
disabled={!value}
|
||||
type='radio'
|
||||
value={2}
|
||||
>
|
||||
>
|
||||
{offLabel}
|
||||
</TB>
|
||||
</BSBG>
|
||||
|
@ -10,7 +10,7 @@ function BlockSaveButton({ children, ...restProps }) {
|
||||
bsStyle='primary'
|
||||
type='submit'
|
||||
{...restProps}
|
||||
>
|
||||
>
|
||||
{children || 'Save'}
|
||||
</Button>
|
||||
);
|
||||
|
@ -155,7 +155,7 @@ class DefaultLayout extends Component {
|
||||
},
|
||||
{ name: 'keywords', content: metaKeywords.join(', ') }
|
||||
]}
|
||||
>
|
||||
>
|
||||
<style>{fontawesome.dom.css()}</style>
|
||||
</Helmet>
|
||||
<Header disableSettings={disableSettings} />
|
||||
|
@ -75,7 +75,7 @@ class GuideLayout extends React.Component {
|
||||
md={4}
|
||||
smHidden={!displaySideNav}
|
||||
xsHidden={!displaySideNav}
|
||||
>
|
||||
>
|
||||
<SideNav
|
||||
expandedState={expandedState}
|
||||
onNavigate={this.handleNavigation}
|
||||
@ -88,13 +88,13 @@ class GuideLayout extends React.Component {
|
||||
md={8}
|
||||
smHidden={displaySideNav}
|
||||
xsHidden={displaySideNav}
|
||||
>
|
||||
>
|
||||
<main
|
||||
className='content'
|
||||
id='main'
|
||||
ref={this.getContentRef}
|
||||
tabIndex='-1'
|
||||
>
|
||||
>
|
||||
{this.props.children}
|
||||
</main>
|
||||
</Col>
|
||||
|
@ -29,7 +29,7 @@ function NoArticles() {
|
||||
}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
write one?
|
||||
</a>
|
||||
</span>
|
||||
@ -92,7 +92,7 @@ class NavPanel extends Component {
|
||||
bsClass='panelStyle panel'
|
||||
id={`${dashedName}-panel`}
|
||||
role='listitem'
|
||||
>
|
||||
>
|
||||
<Panel.Heading>{this.renderHeader()}</Panel.Heading>
|
||||
{isExpanded ? <Panel.Body>{this.renderBody()}</Panel.Body> : null}
|
||||
</Panel>
|
||||
|
@ -57,7 +57,7 @@ class SideNav extends Component {
|
||||
path={parent.path}
|
||||
title={title}
|
||||
toggleDisplaySideNav={this.props.toggleDisplaySideNav}
|
||||
>
|
||||
>
|
||||
{children}
|
||||
</NavPanel>
|
||||
);
|
||||
|
@ -81,7 +81,7 @@ function renderSettingsButton() {
|
||||
bsSize='lg'
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
>
|
||||
>
|
||||
Update my settings
|
||||
</Button>
|
||||
</Link>
|
||||
|
@ -123,7 +123,7 @@ function renderCertShow(username, cert) {
|
||||
bsSize='lg'
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
>
|
||||
>
|
||||
View {cert.title}
|
||||
</Button>
|
||||
</Link>
|
||||
|
@ -140,7 +140,7 @@ class Timeline extends Component {
|
||||
aria-labelledby='contained-modal-title'
|
||||
onHide={this.closeSolution}
|
||||
show={solutionOpen}
|
||||
>
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title id='contained-modal-title'>
|
||||
{`${username}'s Solution to ${blockNameify(idToNameMap[id])}`}
|
||||
|
@ -142,7 +142,7 @@ class CertificationSettings extends Component {
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
onClick={onClickHandler}
|
||||
>
|
||||
>
|
||||
Show Code
|
||||
</Button>
|
||||
);
|
||||
@ -156,13 +156,13 @@ class CertificationSettings extends Component {
|
||||
className='btn-invert'
|
||||
id={`dropdown-for-${projectId}`}
|
||||
title='Show Solutions'
|
||||
>
|
||||
>
|
||||
<MenuItem
|
||||
bsStyle='primary'
|
||||
href={solution}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Front End
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
@ -170,7 +170,7 @@ class CertificationSettings extends Component {
|
||||
href={githubLink}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Back End
|
||||
</MenuItem>
|
||||
</DropdownButton>
|
||||
@ -186,7 +186,7 @@ class CertificationSettings extends Component {
|
||||
href={solution}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Show Solution
|
||||
</Button>
|
||||
);
|
||||
@ -197,7 +197,7 @@ class CertificationSettings extends Component {
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
onClick={onClickHandler}
|
||||
>
|
||||
>
|
||||
Show Code
|
||||
</Button>
|
||||
);
|
||||
@ -258,7 +258,7 @@ class CertificationSettings extends Component {
|
||||
bsStyle='primary'
|
||||
href={certLocation}
|
||||
onClick={createClickHandler(superBlock)}
|
||||
>
|
||||
>
|
||||
{isCert ? 'Show Certification' : 'Claim Certification'}
|
||||
</Button>
|
||||
</td>
|
||||
@ -280,7 +280,7 @@ class CertificationSettings extends Component {
|
||||
bsSize='large'
|
||||
onHide={this.handleSolutionModalHide}
|
||||
show={isOpen}
|
||||
>
|
||||
>
|
||||
<Modal.Header className='this-one?' closeButton={true}>
|
||||
<Modal.Title id='solution-viewer-modal-title'>
|
||||
Solution for {projectTitle}
|
||||
|
@ -189,7 +189,7 @@ class EmailSettings extends Component {
|
||||
<FormGroup
|
||||
controlId='new-email'
|
||||
validationState={newEmailValidation}
|
||||
>
|
||||
>
|
||||
<ControlLabel>New Email</ControlLabel>
|
||||
<FormControl
|
||||
onChange={this.createHandleEmailFormChange('newEmail')}
|
||||
@ -203,7 +203,7 @@ class EmailSettings extends Component {
|
||||
<FormGroup
|
||||
controlId='confirm-email'
|
||||
validationState={confirmEmailValidation}
|
||||
>
|
||||
>
|
||||
<ControlLabel>Confirm New Email</ControlLabel>
|
||||
<FormControl
|
||||
onChange={this.createHandleEmailFormChange('confirmNewEmail')}
|
||||
|
@ -96,7 +96,7 @@ class InternetSettings extends Component {
|
||||
<FormGroup
|
||||
controlId='internet-github'
|
||||
validationState={this.getValidationStateFor(githubProfile)}
|
||||
>
|
||||
>
|
||||
<ControlLabel>
|
||||
<strong>GitHub</strong>
|
||||
</ControlLabel>
|
||||
@ -109,7 +109,7 @@ class InternetSettings extends Component {
|
||||
<FormGroup
|
||||
controlId='internet-linkedin'
|
||||
validationState={this.getValidationStateFor(linkedin)}
|
||||
>
|
||||
>
|
||||
<ControlLabel>
|
||||
<strong>LinkedIn</strong>
|
||||
</ControlLabel>
|
||||
@ -122,7 +122,7 @@ class InternetSettings extends Component {
|
||||
<FormGroup
|
||||
controlId='internet-picture'
|
||||
validationState={this.getValidationStateFor(twitter)}
|
||||
>
|
||||
>
|
||||
<ControlLabel>
|
||||
<strong>Twitter</strong>
|
||||
</ControlLabel>
|
||||
@ -135,7 +135,7 @@ class InternetSettings extends Component {
|
||||
<FormGroup
|
||||
controlId='internet-website'
|
||||
validationState={this.getValidationStateFor(website)}
|
||||
>
|
||||
>
|
||||
<ControlLabel>
|
||||
<strong>Personal Website</strong>
|
||||
</ControlLabel>
|
||||
|
@ -177,7 +177,7 @@ class PortfolioSettings extends Component {
|
||||
if (isImage && !maybeUrl) {
|
||||
return { state: null, message: '' };
|
||||
}
|
||||
if (isImage && !(/\.(png|jpg|jpeg|gif)$/).test(maybeUrl)) {
|
||||
if (isImage && !/\.(png|jpg|jpeg|gif)$/.test(maybeUrl)) {
|
||||
return {
|
||||
state: 'error',
|
||||
message: 'URL must link directly to an image file'
|
||||
@ -214,7 +214,7 @@ class PortfolioSettings extends Component {
|
||||
validationState={
|
||||
pristine || (!pristine && !title) ? null : titleState
|
||||
}
|
||||
>
|
||||
>
|
||||
<ControlLabel>Title</ControlLabel>
|
||||
<FormControl
|
||||
onChange={this.createOnChangeHandler(id, 'title')}
|
||||
@ -229,7 +229,7 @@ class PortfolioSettings extends Component {
|
||||
validationState={
|
||||
pristine || (!pristine && !url) ? null : urlState
|
||||
}
|
||||
>
|
||||
>
|
||||
<ControlLabel>URL</ControlLabel>
|
||||
<FormControl
|
||||
onChange={this.createOnChangeHandler(id, 'url')}
|
||||
@ -242,7 +242,7 @@ class PortfolioSettings extends Component {
|
||||
<FormGroup
|
||||
controlId={`${id}-image`}
|
||||
validationState={pristine ? null : imageState}
|
||||
>
|
||||
>
|
||||
<ControlLabel>Image</ControlLabel>
|
||||
<FormControl
|
||||
onChange={this.createOnChangeHandler(id, 'image')}
|
||||
@ -254,7 +254,7 @@ class PortfolioSettings extends Component {
|
||||
<FormGroup
|
||||
controlId={`${id}-description`}
|
||||
validationState={pristine ? null : descriptionState}
|
||||
>
|
||||
>
|
||||
<ControlLabel>Description</ControlLabel>
|
||||
<FormControl
|
||||
componentClass='textarea'
|
||||
@ -277,7 +277,7 @@ class PortfolioSettings extends Component {
|
||||
/* eslint-enable camelcase */
|
||||
})
|
||||
}
|
||||
>
|
||||
>
|
||||
Save this portfolio item
|
||||
</BlockSaveButton>
|
||||
<ButtonSpacer />
|
||||
@ -288,7 +288,7 @@ class PortfolioSettings extends Component {
|
||||
className='btn-delete-portfolio'
|
||||
onClick={() => this.handleRemoveItem(id)}
|
||||
type='button'
|
||||
>
|
||||
>
|
||||
Remove this portfolio item
|
||||
</Button>
|
||||
</form>
|
||||
@ -325,7 +325,7 @@ class PortfolioSettings extends Component {
|
||||
bsStyle='primary'
|
||||
onClick={this.handleAdd}
|
||||
type='button'
|
||||
>
|
||||
>
|
||||
Add a new portfolio Item
|
||||
</Button>
|
||||
</FullWidthRow>
|
||||
|
@ -14,10 +14,13 @@ import Spacer from '../helpers/Spacer';
|
||||
import ToggleSetting from './ToggleSetting';
|
||||
import SectionHeader from './SectionHeader';
|
||||
|
||||
const mapStateToProps = createSelector(userSelector, user => ({
|
||||
...user.profileUI,
|
||||
user
|
||||
}));
|
||||
const mapStateToProps = createSelector(
|
||||
userSelector,
|
||||
user => ({
|
||||
...user.profileUI,
|
||||
user
|
||||
})
|
||||
);
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators({ submitProfileUI }, dispatch);
|
||||
@ -130,7 +133,7 @@ class PrivacySettings extends Component {
|
||||
toggleFlag={this.toggleFlag('showLocation')}
|
||||
/>
|
||||
<ToggleSetting
|
||||
action='My "about me"'
|
||||
action='My "about me"'
|
||||
flag={!showAbout}
|
||||
flagName='showAbout'
|
||||
offLabel='Public'
|
||||
@ -203,7 +206,7 @@ class PrivacySettings extends Component {
|
||||
href={`data:text/json;charset=utf-8,${encodeURIComponent(
|
||||
JSON.stringify(user)
|
||||
)}`}
|
||||
>
|
||||
>
|
||||
Download your data
|
||||
</Button>
|
||||
</FullWidthRow>
|
||||
|
@ -42,7 +42,7 @@ function SolutionViewer({
|
||||
bsStyle='primary'
|
||||
className='solution-viewer'
|
||||
key={solution.slice(0, 10)}
|
||||
>
|
||||
>
|
||||
<Panel.Heading>JS</Panel.Heading>
|
||||
<Panel.Body>
|
||||
<pre>
|
||||
|
@ -91,9 +91,8 @@ class UsernameSettings extends Component {
|
||||
characterValidation: { valid }
|
||||
} = this.state;
|
||||
|
||||
return this.setState(
|
||||
{ submitClicked: true },
|
||||
() => (valid ? submitNewUsername(formValue) : null)
|
||||
return this.setState({ submitClicked: true }, () =>
|
||||
valid ? submitNewUsername(formValue) : null
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ class NavigationContextProvider extends Component {
|
||||
toggleDisplaySideNav: noop,
|
||||
toggleExpandedState: this.toggleExpandedState
|
||||
}}
|
||||
>
|
||||
>
|
||||
{children}
|
||||
</Provider>
|
||||
);
|
||||
|
@ -101,13 +101,13 @@ class AcceptPrivacyTerms extends Component {
|
||||
id='terms-of-service'
|
||||
inline={true}
|
||||
onChange={this.createHandleChange('termsOfService')}
|
||||
>
|
||||
>
|
||||
I accept the{' '}
|
||||
<a
|
||||
href='https://www.freecodecamp/terms'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
terms of service
|
||||
</a>{' '}
|
||||
(required)
|
||||
@ -123,13 +123,13 @@ class AcceptPrivacyTerms extends Component {
|
||||
id='privacy-policy'
|
||||
inline={true}
|
||||
onChange={this.createHandleChange('privacyPolicy')}
|
||||
>
|
||||
>
|
||||
I accept the{' '}
|
||||
<a
|
||||
href='https://www.freecodecamp/privacy'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
privacy policy
|
||||
</a>{' '}
|
||||
(required)
|
||||
@ -145,7 +145,7 @@ class AcceptPrivacyTerms extends Component {
|
||||
id='quincy-email'
|
||||
inline={true}
|
||||
onChange={this.createHandleChange('quincyEmail')}
|
||||
>
|
||||
>
|
||||
I want weekly emails from Quincy, freeCodeCamp.org's
|
||||
founder.
|
||||
</Checkbox>
|
||||
@ -157,7 +157,7 @@ class AcceptPrivacyTerms extends Component {
|
||||
className='big-cta-btn'
|
||||
disabled={!privacyPolicy || !termsOfService}
|
||||
type='submit'
|
||||
>
|
||||
>
|
||||
Continue to freeCodeCamp
|
||||
</Button>
|
||||
</form>
|
||||
|
@ -68,7 +68,7 @@ class DonateOtherPage extends Component {
|
||||
})
|
||||
}
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
<input defaultValue='_s-xclick' name='cmd' type='hidden' />{' '}
|
||||
<input
|
||||
defaultValue={item.defaultValueHash}
|
||||
|
@ -35,7 +35,7 @@ function Index() {
|
||||
href='https://freecodecamp.org'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
freeCodeCamp.org
|
||||
</a>
|
||||
{'. It has a curriculum that starts from zero and helps you learn' +
|
||||
@ -48,7 +48,7 @@ function Index() {
|
||||
href='https://github.com/freeCodeCamp/freeCodeCamp'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
open source
|
||||
</a>
|
||||
{'. Your help in making it better is greatly appreciated!'}
|
||||
|
@ -232,7 +232,7 @@ const IndexPage = () => (
|
||||
href='https://donate.freecodecamp.org/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
make a tax-deductible donation here
|
||||
</a>
|
||||
</p>
|
||||
|
@ -53,7 +53,7 @@ const IndexPage = ({
|
||||
href='https://donate.freecodecamp.org'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
donate
|
||||
</a>{' '}
|
||||
to our nonprofit.
|
||||
|
@ -30,7 +30,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://givecamp.org/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Give Camp
|
||||
</a>
|
||||
</li>
|
||||
@ -39,7 +39,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.volunteermatch.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Volunteer Match.com
|
||||
</a>
|
||||
</li>
|
||||
@ -48,7 +48,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.catchafire.org'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Catchafire
|
||||
</a>
|
||||
</li>
|
||||
@ -57,7 +57,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://anyonecanhaveawebsite.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Anyone Can Have A Website
|
||||
</a>
|
||||
</li>
|
||||
@ -69,7 +69,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://www.youtube.com/watch?v=4AXDKWuY9QM'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
How to build and deploy a website without writing any code for
|
||||
free
|
||||
</a>
|
||||
@ -79,7 +79,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.wix.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Wix
|
||||
</a>
|
||||
</li>
|
||||
@ -88,7 +88,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://www.squarespace.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Square Space
|
||||
</a>
|
||||
</li>
|
||||
@ -97,7 +97,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://wordpress.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
WordPress
|
||||
</a>
|
||||
</li>
|
||||
@ -106,7 +106,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://xprs.imcreator.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Imcreator.com
|
||||
</a>
|
||||
</li>
|
||||
@ -118,7 +118,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://causesignal.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Cause Signal
|
||||
</a>
|
||||
</li>
|
||||
@ -127,7 +127,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://www.thedatabank.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
The Data Bank
|
||||
</a>
|
||||
</li>
|
||||
@ -136,7 +136,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.donorsnap.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Donor Snap
|
||||
</a>
|
||||
</li>
|
||||
@ -145,7 +145,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.donorperfect.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Donor Perfect
|
||||
</a>
|
||||
</li>
|
||||
@ -157,7 +157,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
E Tapestry
|
||||
</a>
|
||||
</li>
|
||||
@ -166,7 +166,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.z2systems.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Z2 Systems
|
||||
</a>
|
||||
</li>
|
||||
@ -175,7 +175,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.regpacks.com/volunteer-management'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Reg Packs
|
||||
</a>
|
||||
</li>
|
||||
@ -184,7 +184,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://sumac.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Sumac
|
||||
</a>
|
||||
</li>
|
||||
@ -193,7 +193,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.volgistics.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Volgistics
|
||||
</a>
|
||||
</li>
|
||||
@ -205,7 +205,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://www.ordoro.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Ordoro
|
||||
</a>
|
||||
</li>
|
||||
@ -214,7 +214,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.unleashedsoftware.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Unleashed Software
|
||||
</a>
|
||||
</li>
|
||||
@ -223,7 +223,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://www.ezofficeinventory.com/industries/non-profits'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
EZ Office Inventory
|
||||
</a>
|
||||
</li>
|
||||
@ -235,7 +235,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.dokeos.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Dokeos
|
||||
</a>
|
||||
</li>
|
||||
@ -244,7 +244,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.efrontlearning.net/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
E Front Learning
|
||||
</a>
|
||||
</li>
|
||||
@ -253,7 +253,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://moodle.org/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Moodle
|
||||
</a>
|
||||
</li>
|
||||
@ -262,7 +262,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://sakaiproject.org/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Sakai Project
|
||||
</a>
|
||||
</li>
|
||||
@ -274,7 +274,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='https://civicrm.org/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
CiviCRM
|
||||
</a>
|
||||
</li>
|
||||
@ -283,7 +283,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://tcmgr.com/'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Total Community Manager
|
||||
</a>
|
||||
</li>
|
||||
@ -295,7 +295,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.google.com/forms'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Google Forms
|
||||
</a>
|
||||
</li>
|
||||
@ -304,7 +304,7 @@ function SoftwareResourcesForNonProfits() {
|
||||
href='http://www.typeform.com'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Typeform
|
||||
</a>
|
||||
</li>
|
||||
|
@ -92,12 +92,12 @@ class UpdateEmail extends Component {
|
||||
<FormGroup
|
||||
controlId='emailInput'
|
||||
validationState={this.getEmailValidationState()}
|
||||
>
|
||||
>
|
||||
<Col
|
||||
className='email-label'
|
||||
componentClass={ControlLabel}
|
||||
sm={2}
|
||||
>
|
||||
>
|
||||
Email
|
||||
</Col>
|
||||
<Col sm={10}>
|
||||
@ -115,7 +115,7 @@ class UpdateEmail extends Component {
|
||||
bsStyle='primary'
|
||||
disabled={this.getEmailValidationState() !== 'success'}
|
||||
type='submit'
|
||||
>
|
||||
>
|
||||
{isNewEmail ? 'Update my Email' : 'Verify Email'}
|
||||
</Button>
|
||||
</Form>
|
||||
|
@ -43,7 +43,7 @@ class DesktopLayout extends Component {
|
||||
renderOnResize={true}
|
||||
renderOnResizeRate={20}
|
||||
{...resizeProps}
|
||||
>
|
||||
>
|
||||
{editor}
|
||||
</ReflexElement>
|
||||
<ReflexSplitter propagate={true} {...resizeProps} />
|
||||
@ -53,7 +53,7 @@ class DesktopLayout extends Component {
|
||||
renderOnResize={true}
|
||||
renderOnResizeRate={20}
|
||||
{...resizeProps}
|
||||
>
|
||||
>
|
||||
{testOutput}
|
||||
</ReflexElement>
|
||||
</ReflexContainer>
|
||||
|
@ -58,7 +58,7 @@ class MobileLayout extends Component {
|
||||
defaultActiveKey={1}
|
||||
id='challenge-page-tabs'
|
||||
onSelect={moveToTab}
|
||||
>
|
||||
>
|
||||
<TabPane eventKey={1} title='Instructions'>
|
||||
{instructions}
|
||||
</TabPane>
|
||||
|
@ -10,7 +10,7 @@ const propTypes = {
|
||||
};
|
||||
|
||||
function emptyInstruction(instructions) {
|
||||
return (/^<section\s+id\s*=\s*("|')instructions\1\s*>\s*<\/section>$/).test(
|
||||
return /^<section\s+id\s*=\s*("|')instructions\1\s*>\s*<\/section>$/.test(
|
||||
instructions
|
||||
);
|
||||
}
|
||||
|
@ -120,11 +120,11 @@ export class CompletionModal extends Component {
|
||||
onHide={close}
|
||||
onKeyDown={isOpen ? handleKeypress : noop}
|
||||
show={isOpen}
|
||||
>
|
||||
>
|
||||
<Modal.Header
|
||||
className='challenge-list-header fcc-modal'
|
||||
closeButton={true}
|
||||
>
|
||||
>
|
||||
<Modal.Title className='text-center'>{message}</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className='completion-modal-body'>
|
||||
@ -138,7 +138,7 @@ export class CompletionModal extends Component {
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
onClick={submitChallenge}
|
||||
>
|
||||
>
|
||||
Submit and go to next challenge{' '}
|
||||
<span className='hidden-xs'>(Ctrl + Enter)</span>
|
||||
</Button>
|
||||
@ -150,7 +150,7 @@ export class CompletionModal extends Component {
|
||||
className='btn-invert'
|
||||
download={`${dashedName}.json`}
|
||||
href={this.state.downloadURL}
|
||||
>
|
||||
>
|
||||
Download my solution
|
||||
</Button>
|
||||
) : null}
|
||||
|
@ -37,7 +37,7 @@ export class HelpModal extends Component {
|
||||
<Modal.Header
|
||||
className='help-modal-header fcc-modal'
|
||||
closeButton={true}
|
||||
>
|
||||
>
|
||||
<Modal.Title className='text-center'>Ask for help?</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className='help-modal-body text-center'>
|
||||
@ -48,7 +48,7 @@ export class HelpModal extends Component {
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
title='Read, search, ask'
|
||||
>
|
||||
>
|
||||
Read-Search-Ask
|
||||
</a>
|
||||
method, then you can ask for help on the freeCodeCamp forum.
|
||||
@ -58,7 +58,7 @@ export class HelpModal extends Component {
|
||||
bsSize='lg'
|
||||
bsStyle='primary'
|
||||
onClick={createQuestion}
|
||||
>
|
||||
>
|
||||
Create a help post on the forum
|
||||
</Button>
|
||||
<Button
|
||||
@ -66,7 +66,7 @@ export class HelpModal extends Component {
|
||||
bsSize='lg'
|
||||
bsStyle='primary'
|
||||
onClick={closeHelpModal}
|
||||
>
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Modal.Body>
|
||||
|
@ -16,9 +16,12 @@ const propTypes = {
|
||||
reset: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = createSelector(isResetModalOpenSelector, isOpen => ({
|
||||
isOpen
|
||||
}));
|
||||
const mapStateToProps = createSelector(
|
||||
isResetModalOpenSelector,
|
||||
isOpen => ({
|
||||
isOpen
|
||||
})
|
||||
);
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
@ -41,7 +44,7 @@ function ResetModal({ reset, close, isOpen }) {
|
||||
keyboard={true}
|
||||
onHide={close}
|
||||
show={isOpen}
|
||||
>
|
||||
>
|
||||
<Modal.Header className='reset-modal-header' closeButton={true}>
|
||||
<Modal.Title className='text-center'>Reset this lesson?</Modal.Title>
|
||||
</Modal.Header>
|
||||
@ -62,7 +65,7 @@ function ResetModal({ reset, close, isOpen }) {
|
||||
bsSize='large'
|
||||
bsStyle='danger'
|
||||
onClick={withActions(reset, close)}
|
||||
>
|
||||
>
|
||||
Reset this Lesson
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
|
@ -13,9 +13,12 @@ import { initConsole, challengeTestsSelector } from '../redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import './side-panel.css';
|
||||
|
||||
const mapStateToProps = createSelector(challengeTestsSelector, tests => ({
|
||||
tests
|
||||
}));
|
||||
const mapStateToProps = createSelector(
|
||||
challengeTestsSelector,
|
||||
tests => ({
|
||||
tests
|
||||
})
|
||||
);
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
|
@ -38,7 +38,7 @@ function TestSuite({ tests }) {
|
||||
className='test-result'
|
||||
key={text.slice(-6) + index}
|
||||
tabIndex='0'
|
||||
>
|
||||
>
|
||||
<div className='test-status-icon'>
|
||||
{isInitial ? <Initial /> : statusIcon}
|
||||
</div>
|
||||
|
@ -45,7 +45,7 @@ function ToolPanel({
|
||||
className={`tool-panel-group ${
|
||||
isMobile ? 'tool-panel-group-mobile' : ''
|
||||
}`}
|
||||
>
|
||||
>
|
||||
<Button block={true} bsStyle='primary' onClick={executeChallenge}>
|
||||
{isMobile ? 'Run' : 'Run the Tests'}
|
||||
</Button>
|
||||
@ -54,7 +54,7 @@ function ToolPanel({
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
onClick={openResetModal}
|
||||
>
|
||||
>
|
||||
{isMobile ? 'Reset' : 'Reset All Code'}
|
||||
</Button>
|
||||
{guideUrl ? (
|
||||
@ -64,7 +64,7 @@ function ToolPanel({
|
||||
className='btn-invert'
|
||||
href={guideUrl}
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
{isMobile ? 'Hint' : 'Get a hint'}
|
||||
</Button>
|
||||
) : null}
|
||||
@ -74,7 +74,7 @@ function ToolPanel({
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
onClick={openVideoModal}
|
||||
>
|
||||
>
|
||||
{isMobile ? 'Video' : 'Watch a video'}
|
||||
</Button>
|
||||
) : null}
|
||||
@ -83,7 +83,7 @@ function ToolPanel({
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
onClick={openHelpModal}
|
||||
>
|
||||
>
|
||||
{isMobile ? 'Help' : 'Ask for help'}
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -30,11 +30,11 @@ export class VideoModal extends Component {
|
||||
dialogClassName='video-modal'
|
||||
onHide={closeVideoModal}
|
||||
show={isOpen}
|
||||
>
|
||||
>
|
||||
<Modal.Header
|
||||
className='video-modal-header fcc-modal'
|
||||
closeButton={true}
|
||||
>
|
||||
>
|
||||
<Modal.Title className='text-center'>Watch A Video</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className='video-modal-body'>
|
||||
|
@ -7,7 +7,7 @@ function RedFail() {
|
||||
viewBox='0 0 200 200'
|
||||
width='50'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
>
|
||||
<g>
|
||||
<title>Test failed</title>
|
||||
<circle
|
||||
|
@ -12,7 +12,7 @@ function GreenNotCompleted(props) {
|
||||
width='50'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
{...props}
|
||||
>
|
||||
>
|
||||
<g>
|
||||
<title>Not Passed</title>
|
||||
<circle
|
||||
|
@ -10,7 +10,7 @@ function GreenPass(props) {
|
||||
width='50'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
{...props}
|
||||
>
|
||||
>
|
||||
<g>
|
||||
<title>Passed</title>
|
||||
<circle
|
||||
|
@ -8,7 +8,7 @@ function Initial(props) {
|
||||
width='50'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
{...props}
|
||||
>
|
||||
>
|
||||
<g>
|
||||
<title>Initial</title>
|
||||
<circle
|
||||
@ -26,7 +26,7 @@ function Initial(props) {
|
||||
viewBox='-13 -12 50 50'
|
||||
width='200'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
>
|
||||
<path
|
||||
d={
|
||||
'M8 1c0-.552.448-1 1-1h6c.553 0 1 .448 1 1s-.447 1-1 1h-6c-' +
|
||||
|
@ -35,7 +35,7 @@ export class ToolPanel extends Component {
|
||||
className='btn-invert'
|
||||
href={guideUrl}
|
||||
target='_blank'
|
||||
>
|
||||
>
|
||||
Get a hint
|
||||
</Button>
|
||||
)}
|
||||
@ -44,7 +44,7 @@ export class ToolPanel extends Component {
|
||||
bsStyle='primary'
|
||||
className='btn-invert'
|
||||
onClick={openHelpModal}
|
||||
>
|
||||
>
|
||||
Ask for help
|
||||
</Button>
|
||||
</div>
|
||||
@ -59,4 +59,3 @@ export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ToolPanel);
|
||||
|
||||
|
@ -105,18 +105,20 @@ function loadCodeEpic(action$, state$) {
|
||||
const codeFound = getCode(id);
|
||||
if (codeFound && isFilesAllPoly(codeFound)) {
|
||||
finalFiles = {
|
||||
...fileKeys.map(key => files[key]).reduce(
|
||||
(files, file) => ({
|
||||
...files,
|
||||
[file.key]: {
|
||||
...file,
|
||||
contents: codeFound[file.key]
|
||||
? codeFound[file.key].contents
|
||||
: file.contents
|
||||
}
|
||||
}),
|
||||
{}
|
||||
)
|
||||
...fileKeys
|
||||
.map(key => files[key])
|
||||
.reduce(
|
||||
(files, file) => ({
|
||||
...files,
|
||||
[file.key]: {
|
||||
...file,
|
||||
contents: codeFound[file.key]
|
||||
? codeFound[file.key].contents
|
||||
: file.contents
|
||||
}
|
||||
}),
|
||||
{}
|
||||
)
|
||||
};
|
||||
} else {
|
||||
const legacyCode = getLegacyCode(legacyKey);
|
||||
|
@ -92,7 +92,7 @@ function getJSTestRunner({ build, sources }, proxyLogger) {
|
||||
|
||||
const testWorker = createWorker('test-evaluator');
|
||||
|
||||
return async(testString, testTimeout) => {
|
||||
return async (testString, testTimeout) => {
|
||||
try {
|
||||
testWorker.on('LOG', proxyLogger);
|
||||
return await testWorker.execute(
|
||||
|
@ -98,7 +98,7 @@ const initTestFrame = frameReady => ctx => {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
contentLoaded.then(async() => {
|
||||
contentLoaded.then(async () => {
|
||||
const { sources, loadEnzyme } = ctx;
|
||||
// default for classic challenges
|
||||
// should not be used for modern
|
||||
|
@ -23,11 +23,13 @@ const propTypes = {
|
||||
};
|
||||
|
||||
function renderMenuItems({ edges = [] }) {
|
||||
return edges.map(({ node }) => node).map(({ title, fields: { slug } }) => (
|
||||
<Link key={'intro-' + slug} to={slug}>
|
||||
<ListGroupItem>{title}</ListGroupItem>
|
||||
</Link>
|
||||
));
|
||||
return edges
|
||||
.map(({ node }) => node)
|
||||
.map(({ title, fields: { slug } }) => (
|
||||
<Link key={'intro-' + slug} to={slug}>
|
||||
<ListGroupItem>{title}</ListGroupItem>
|
||||
</Link>
|
||||
));
|
||||
}
|
||||
|
||||
function IntroductionPage({ data: { markdownRemark, allChallengeNode } }) {
|
||||
@ -55,7 +57,7 @@ function IntroductionPage({ data: { markdownRemark, allChallengeNode } }) {
|
||||
<Link
|
||||
className='btn btn-lg btn-primary btn-block'
|
||||
to={firstLessonPath}
|
||||
>
|
||||
>
|
||||
Go to the first lesson
|
||||
</Link>
|
||||
<ButtonSpacer />
|
||||
|
@ -43,7 +43,7 @@ async function translateChallenge(file) {
|
||||
translateText(instructions),
|
||||
...tests.map(
|
||||
test =>
|
||||
new Promise(async(resolve, reject) => {
|
||||
new Promise(async (resolve, reject) => {
|
||||
const { testString, text } = test;
|
||||
const translatedText = await translateText(text).catch(reject);
|
||||
return resolve({
|
||||
@ -58,11 +58,11 @@ async function translateChallenge(file) {
|
||||
const { files = {}, solutions = [], ...challengeMeta } = challenge;
|
||||
const md = `---
|
||||
${YAML.dump(
|
||||
Object.assign(challengeMeta, {
|
||||
localeTitle: title ? title.join(' ').trim() : ''
|
||||
}),
|
||||
{ lineWidth: 10000 }
|
||||
)}---
|
||||
Object.assign(challengeMeta, {
|
||||
localeTitle: title ? title.join(' ').trim() : ''
|
||||
}),
|
||||
{ lineWidth: 10000 }
|
||||
)}---
|
||||
|
||||
## Description
|
||||
${description}
|
||||
@ -88,20 +88,20 @@ ${generateChallengeSeed(files)}
|
||||
<section id='solution'>
|
||||
|
||||
${
|
||||
solutions.length === 0
|
||||
? `\`\`\`js
|
||||
solutions.length === 0
|
||||
? `\`\`\`js
|
||||
// solution required
|
||||
\`\`\``
|
||||
: solutions
|
||||
.map(
|
||||
solution => `
|
||||
: solutions
|
||||
.map(
|
||||
solution => `
|
||||
\`\`\`js
|
||||
${solution}
|
||||
\`\`\`
|
||||
`
|
||||
)
|
||||
.join('\n')
|
||||
}
|
||||
)
|
||||
.join('\n')
|
||||
}
|
||||
</section>
|
||||
`;
|
||||
|
||||
@ -126,8 +126,8 @@ ${contents}
|
||||
|
||||
</div>
|
||||
${
|
||||
head.length
|
||||
? `
|
||||
head.length
|
||||
? `
|
||||
### Before Test
|
||||
<div id='${ext}-setup'>
|
||||
|
||||
@ -136,11 +136,11 @@ ${head}
|
||||
\`\`\`
|
||||
|
||||
</div>`
|
||||
: ''
|
||||
}
|
||||
: ''
|
||||
}
|
||||
${
|
||||
tail.length
|
||||
? `
|
||||
tail.length
|
||||
? `
|
||||
### After Test
|
||||
<div id='${ext}-teardown'>
|
||||
|
||||
@ -149,8 +149,8 @@ console.info('after the test');
|
||||
\`\`\`
|
||||
|
||||
</div>`
|
||||
: ''
|
||||
}
|
||||
: ''
|
||||
}
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ async function createTestRunnerForDOMChallenge(
|
||||
await context.reload();
|
||||
await context.setContent(build);
|
||||
await context.evaluate(
|
||||
async(sources, loadEnzyme) => {
|
||||
async (sources, loadEnzyme) => {
|
||||
const code = sources && 'index' in sources ? sources['index'] : '';
|
||||
const getUserInput = fileName => sources[fileName];
|
||||
await document.__initTestFrame({ code, getUserInput, loadEnzyme });
|
||||
@ -298,7 +298,7 @@ async function createTestRunnerForDOMChallenge(
|
||||
loadEnzyme
|
||||
);
|
||||
|
||||
return async({ text, testString }) => {
|
||||
return async ({ text, testString }) => {
|
||||
try {
|
||||
const { pass, err } = await Promise.race([
|
||||
new Promise((_, reject) => setTimeout(() => reject('timeout'), 5000)),
|
||||
@ -327,7 +327,7 @@ async function createTestRunnerForJSChallenge({ files }, solution) {
|
||||
const code = sources && 'index' in sources ? sources['index'] : '';
|
||||
|
||||
const testWorker = createWorker('test-evaluator');
|
||||
return async({ text, testString }) => {
|
||||
return async ({ text, testString }) => {
|
||||
try {
|
||||
const { pass, err } = await testWorker.execute(
|
||||
{ testString, build, code, sources },
|
||||
|
@ -45,7 +45,7 @@ function textToData(sectionIds) {
|
||||
const lines = child.value.split('\n');
|
||||
if (lines.filter(Boolean).length > 0) {
|
||||
lines.forEach((line, index) => {
|
||||
if ((/^\s*$/).test(line)) {
|
||||
if (/^\s*$/.test(line)) {
|
||||
currentParagraph = null;
|
||||
} else {
|
||||
if (!currentParagraph || index > 0) {
|
||||
|
@ -70,7 +70,7 @@ const challengeFrontmatterValidator = file => frontmatter => {
|
||||
|
||||
function isChallengeParseable(file) {
|
||||
const { stat, fullPath } = file;
|
||||
if (!stat.isFile() || (/_meta/).test(fullPath)) {
|
||||
if (!stat.isFile() || /_meta/.test(fullPath)) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return parseMarkdown(fullPath);
|
||||
|
Loading…
x
Reference in New Issue
Block a user