diff --git a/client/sagas/execute-challenge-saga.js b/client/sagas/execute-challenge-saga.js index ab7b9ac8a4..96b7c6e566 100644 --- a/client/sagas/execute-challenge-saga.js +++ b/client/sagas/execute-challenge-saga.js @@ -1,5 +1,8 @@ import { Scheduler, Observable } from 'rx'; +import { + challengeSelector +} from '../../common/app/routes/challenges/redux/selectors'; import { ajax$ } from '../../common/utils/ajax-stream'; import throwers from '../rechallenge/throwers'; import transformers from '../rechallenge/transformers'; @@ -25,10 +28,7 @@ const globalRequires = [{ link: 'https://cdnjs.cloudflare.com/' + 'ajax/libs/normalize/4.2.0/normalize.min.css' }, { - src: '/bower_components/jquery/dist/jquery.js', - script: true, - type: 'global', - crossDomain: false + src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.js' }]; const scriptCache = new Map(); @@ -36,7 +36,7 @@ const linkCache = new Map(); function cacheScript({ src } = {}, crossDomain = true) { if (!src) { - return Observable.throw(new Error('No source provided for script')); + throw new Error('No source provided for script'); } if (scriptCache.has(src)) { return scriptCache.get(src); @@ -49,7 +49,6 @@ function cacheScript({ src } = {}, crossDomain = true) { }) .map(({ response }) => response) .map(script => ``) - .catch(createErrorObservable) .shareReplay(); scriptCache.set(src, script$); @@ -71,7 +70,7 @@ function cacheLink({ link } = {}, crossDomain = true) { }) .map(({ response }) => response) .map(script => ``) - .catch(createErrorObservable) + .catch(() => Observable.just('')) .shareReplay(); linkCache.set(link, link$); @@ -94,8 +93,10 @@ export default function executeChallengeSaga(action$, getState) { )) .debounce(750) .flatMapLatest(({ type }) => { - const { files, required = [] } = getState().challengesApp; - const finalRequires = [...required, ...globalRequires ]; + const state = getState(); + const { files } = state.challengesApp; + const { challenge: { required = [] } } = challengeSelector(state); + const finalRequires = [...globalRequires, ...required ]; return createFileStream(files) ::throwers() ::transformers() @@ -121,7 +122,7 @@ export default function executeChallengeSaga(action$, getState) { .flatMap(source => { const head$ = Observable.from(finalRequires) .flatMap(required => { - if (required.script) { + if (required.src) { return cacheScript(required, required.crossDomain); } if (required.link) { diff --git a/common/models/challenge.json b/common/models/challenge.json index 9243713cee..94d3c3f21b 100644 --- a/common/models/challenge.json +++ b/common/models/challenge.json @@ -106,6 +106,25 @@ "translations": { "type": "object", "default": "{}" + }, + "required": { + "type": [{ + "type": { + "link": { + "type": "string", + "description": "Used for css files" + }, + "src": { + "type": "string", + "description": "Used for script files" + }, + "crossDomain": { + "type": "boolean", + "description": "Files coming from FreeCodeCamp must mark this true" + } + } + }], + "default": [] } }, "validations": [], diff --git a/seed/challenges/01-front-end-development-certification/bootstrap.json b/seed/challenges/01-front-end-development-certification/bootstrap.json index 0209cf800d..1b88adc1ec 100644 --- a/seed/challenges/01-front-end-development-certification/bootstrap.json +++ b/seed/challenges/01-front-end-development-certification/bootstrap.json @@ -3,6 +3,9 @@ "order": 3, "time": "5 hours", "helpRoom": "Help", + "required": [ + { "link": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css" } + ], "challenges": [ { "id": "bad87fee1348bd9acde08712",