Add hotkey to go to next challenge/bonfire from completion modal, keep editor in focus on exiting completion modal, allow for courseware to theoretically work in production and development.
This commit is contained in:
@ -47,7 +47,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getDoneWithFirst100Hours: function(req, res) {
|
getDoneWithFirst100Hours: function(req, res) {
|
||||||
console.log(req.user.points)
|
|
||||||
if (req.user.points >= 53) {
|
if (req.user.points >= 53) {
|
||||||
res.render('contact/done-with-first-100-hours', {
|
res.render('contact/done-with-first-100-hours', {
|
||||||
title: 'Congratulations on finishing the first 100 hours of Free Code Camp!'
|
title: 'Congratulations on finishing the first 100 hours of Free Code Camp!'
|
||||||
|
@ -86,8 +86,8 @@ exports.returnIndividualCourseware = function(req, res, next) {
|
|||||||
verb: resources.randomVerb(),
|
verb: resources.randomVerb(),
|
||||||
phrase: resources.randomPhrase(),
|
phrase: resources.randomPhrase(),
|
||||||
compliment: resources.randomCompliment(),
|
compliment: resources.randomCompliment(),
|
||||||
coursewareHash: courseware._id
|
coursewareHash: courseware._id,
|
||||||
|
environment: resources.whichEnvironment()
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -247,6 +247,9 @@ module.exports = {
|
|||||||
.map(function(elem) {
|
.map(function(elem) {
|
||||||
return elem.name;
|
return elem.name;
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
whichEnvironment: function() {
|
||||||
|
return process.env.NODE_ENV;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -10,13 +10,7 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor")
|
|||||||
scrollbarStyle: 'null',
|
scrollbarStyle: 'null',
|
||||||
lineWrapping: true,
|
lineWrapping: true,
|
||||||
gutters: ["CodeMirror-lint-markers"],
|
gutters: ["CodeMirror-lint-markers"],
|
||||||
onKeyEvent: doLinting,
|
onKeyEvent: doLinting
|
||||||
extraKeys : {
|
|
||||||
"Ctrl-Enter" : function() {
|
|
||||||
bonfireExecute();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
var editor = myCodeMirror;
|
var editor = myCodeMirror;
|
||||||
editor.setSize("100%", "auto");
|
editor.setSize("100%", "auto");
|
||||||
@ -26,6 +20,10 @@ editor.setOption("extraKeys", {
|
|||||||
Tab: function(cm) {
|
Tab: function(cm) {
|
||||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||||
cm.replaceSelection(spaces);
|
cm.replaceSelection(spaces);
|
||||||
|
},
|
||||||
|
"Ctrl-Enter": function() {
|
||||||
|
bonfireExecute();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,6 +57,7 @@ var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"),
|
|||||||
readOnly: 'nocursor',
|
readOnly: 'nocursor',
|
||||||
lineWrapping: true
|
lineWrapping: true
|
||||||
});
|
});
|
||||||
|
|
||||||
codeOutput.setValue('/**\n' +
|
codeOutput.setValue('/**\n' +
|
||||||
' * Your output will go here.\n' + ' * Console.log() -type statements\n' +
|
' * Your output will go here.\n' + ' * Console.log() -type statements\n' +
|
||||||
' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' +
|
' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' +
|
||||||
@ -243,4 +242,9 @@ function showCompletion() {
|
|||||||
console.log(time);
|
console.log(time);
|
||||||
ga('send', 'event', 'Bonfire', 'solved', bonfireName + ', Time: ' + time +', Attempts: ' + attempts);
|
ga('send', 'event', 'Bonfire', 'solved', bonfireName + ', Time: ' + time +', Attempts: ' + attempts);
|
||||||
$('#complete-bonfire-dialog').modal('show');
|
$('#complete-bonfire-dialog').modal('show');
|
||||||
|
$('#complete-bonfire-dialog').keydown(function(e) {
|
||||||
|
if (e.ctrlKey && e.keyCode == 13) {
|
||||||
|
$('.next-bonfire-button').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
@ -14,13 +14,7 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor")
|
|||||||
scrollbarStyle: 'null',
|
scrollbarStyle: 'null',
|
||||||
lineWrapping: true,
|
lineWrapping: true,
|
||||||
gutters: ["CodeMirror-lint-markers"],
|
gutters: ["CodeMirror-lint-markers"],
|
||||||
onKeyEvent: doLinting,
|
onKeyEvent: doLinting
|
||||||
extraKeys : {
|
|
||||||
"Ctrl-Enter" : function() {
|
|
||||||
bonfireExecute();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
var editor = myCodeMirror;
|
var editor = myCodeMirror;
|
||||||
|
|
||||||
@ -30,6 +24,10 @@ editor.setOption("extraKeys", {
|
|||||||
Tab: function(cm) {
|
Tab: function(cm) {
|
||||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||||
cm.replaceSelection(spaces);
|
cm.replaceSelection(spaces);
|
||||||
|
},
|
||||||
|
"Ctrl-Enter": function() {
|
||||||
|
bonfireExecute();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,20 +50,7 @@ var allTests = '';
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var otherTestsForNow = "<script src='/js/lib/coursewares/iFrameScripts.js'></script>";
|
||||||
|
|
||||||
var coursewareTests = "<script>" +
|
|
||||||
"var allTestsGood = true;" +
|
|
||||||
"var expect = chai.expect; " +
|
|
||||||
"try {" +
|
|
||||||
allTests +
|
|
||||||
"} catch (err) {" +
|
|
||||||
"allTestsGood = false;" +
|
|
||||||
"}" +
|
|
||||||
"if (allTestsGood) {" +
|
|
||||||
"console.log('awesomeSauce');" +
|
|
||||||
"parent.postMessage('CompleteAwesomeSauce', 'http://localhost:3001'); }" +
|
|
||||||
"</script>";
|
|
||||||
|
|
||||||
var delay;
|
var delay;
|
||||||
// Initialize CodeMirror editor with a nice html5 canvas demo.
|
// Initialize CodeMirror editor with a nice html5 canvas demo.
|
||||||
@ -73,12 +58,12 @@ editor.on("change", function () {
|
|||||||
clearTimeout(delay);
|
clearTimeout(delay);
|
||||||
delay = setTimeout(updatePreview, 300);
|
delay = setTimeout(updatePreview, 300);
|
||||||
});
|
});
|
||||||
|
var nodeEnv = prodOrDev === 'production' ? 'http://www.freecodecamp.com' : 'http://localhost:3001';
|
||||||
function updatePreview() {
|
function updatePreview() {
|
||||||
var previewFrame = document.getElementById('preview');
|
var previewFrame = document.getElementById('preview');
|
||||||
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
|
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
|
||||||
preview.open();
|
preview.open();
|
||||||
preview.write(libraryIncludes + editor.getValue() + coursewareTests);
|
preview.write(libraryIncludes + editor.getValue() + otherTestsForNow);
|
||||||
preview.close();
|
preview.close();
|
||||||
}
|
}
|
||||||
setTimeout(updatePreview, 300);
|
setTimeout(updatePreview, 300);
|
||||||
@ -97,28 +82,6 @@ eventer(messageEvent,function(e) {
|
|||||||
}
|
}
|
||||||
},false);
|
},false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), {
|
|
||||||
lineNumbers: false,
|
|
||||||
mode: "text",
|
|
||||||
theme: 'monokai',
|
|
||||||
readOnly: 'nocursor',
|
|
||||||
lineWrapping: true
|
|
||||||
});
|
|
||||||
codeOutput.setValue('/**\n' +
|
|
||||||
' * Your output will go here.\n' + ' * Console.log() -type statements\n' +
|
|
||||||
' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' +
|
|
||||||
' */');
|
|
||||||
codeOutput.setSize("100%", "100%");
|
|
||||||
var info = editor.getScrollInfo();
|
|
||||||
var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top;
|
|
||||||
if (info.top + info.clientHeight < after)
|
|
||||||
editor.scrollTo(null, after - info.clientHeight + 3);
|
|
||||||
|
|
||||||
var editorValue;
|
|
||||||
|
|
||||||
|
|
||||||
var challengeSeed = challengeSeed || null;
|
var challengeSeed = challengeSeed || null;
|
||||||
var tests = tests || [];
|
var tests = tests || [];
|
||||||
var allSeeds = '';
|
var allSeeds = '';
|
||||||
@ -128,7 +91,6 @@ var allSeeds = '';
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
myCodeMirror.setValue(allSeeds);
|
myCodeMirror.setValue(allSeeds);
|
||||||
|
|
||||||
function doLinting () {
|
function doLinting () {
|
||||||
@ -154,133 +116,14 @@ function doLinting () {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#submitButton').on('click', function () {
|
|
||||||
bonfireExecute();
|
|
||||||
});
|
|
||||||
|
|
||||||
function bonfireExecute() {
|
function showCompletion() {
|
||||||
userTests= null;
|
$('#complete-courseware-dialog').modal('show');
|
||||||
$('#codeOutput').empty();
|
$('#complete-courseware-dialog').keydown(function(e) {
|
||||||
var userJavaScript = myCodeMirror.getValue();
|
if (e.ctrlKey && e.keyCode == 13) {
|
||||||
userJavaScript = removeComments(userJavaScript);
|
$('.next-courseware-button').click();
|
||||||
userJavaScript = scrapeTests(userJavaScript);
|
|
||||||
|
|
||||||
submit(userJavaScript, function(cls, message) {
|
|
||||||
if (cls) {
|
|
||||||
codeOutput.setValue(message.error);
|
|
||||||
runTests('Error', null);
|
|
||||||
} else {
|
|
||||||
codeOutput.setValue(message.output);
|
|
||||||
message.input = removeLogs(message.input);
|
|
||||||
runTests(null, message);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var userTests;
|
|
||||||
var testSalt = Math.random();
|
|
||||||
|
|
||||||
|
|
||||||
var scrapeTests = function(userJavaScript) {
|
|
||||||
|
|
||||||
// insert tests from mongo
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
userJavaScript += '\n' + tests[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
var counter = 0;
|
|
||||||
var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/);
|
|
||||||
var match = regex.exec(userJavaScript);
|
|
||||||
while (match != null) {
|
|
||||||
var replacement = '//' + counter + testSalt;
|
|
||||||
userJavaScript = userJavaScript.substring(0, match.index) + replacement + userJavaScript.substring(match.index + match[0].length);
|
|
||||||
|
|
||||||
if (!userTests) {
|
|
||||||
userTests= [];
|
|
||||||
}
|
|
||||||
userTests.push({"text": match[0], "line": counter, "err": null});
|
|
||||||
counter++;
|
|
||||||
match = regex.exec(userJavaScript);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userJavaScript;
|
|
||||||
};
|
|
||||||
|
|
||||||
function removeComments(userJavaScript) {
|
|
||||||
var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|\/\/[^\n]*/g);
|
|
||||||
return userJavaScript.replace(regex, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeLogs(userJavaScript) {
|
|
||||||
return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
var pushed = false;
|
|
||||||
var createTestDisplay = function() {
|
|
||||||
if (pushed) {
|
|
||||||
userTests.pop();
|
|
||||||
}
|
|
||||||
for (var i = 0; i < userTests.length;i++) {
|
|
||||||
var test = userTests[i];
|
|
||||||
var testDoc = document.createElement("div");
|
|
||||||
if (test.err != null) {
|
|
||||||
$(testDoc)
|
|
||||||
.html("<div class='row'><div class='col-xs-1 text-center'><i class='ion-close-circled big-error-icon'></i></div><div class='col-xs-11 test-output wrappable'>" + test.text + "</div><div class='col-xs-11 test-output wrappable'>" + test.err + "</div></div><div class='ten-pixel-break'/>")
|
|
||||||
.prependTo($('#testSuite'))
|
|
||||||
} else {
|
|
||||||
$(testDoc)
|
|
||||||
.html("<div class='row'><div class='col-xs-1 text-center'><i class='ion-checkmark-circled big-success-icon'></i></div><div class='col-xs-11 test-output test-vertical-center wrappable'>" + test.text + "</div></div><div class='ten-pixel-break'/>")
|
|
||||||
.appendTo($('#testSuite'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var assert = chai.assert;
|
|
||||||
var expect = chai.expect;
|
|
||||||
var should = chai.should();
|
|
||||||
|
|
||||||
var reassembleTest = function(test, data) {
|
|
||||||
var lineNum = test.line;
|
|
||||||
var regexp = new RegExp("\/\/" + lineNum + testSalt);
|
|
||||||
return data.input.replace(regexp, test.text);
|
|
||||||
};
|
|
||||||
|
|
||||||
var runTests = function(err, data) {
|
|
||||||
var allTestsPassed = true;
|
|
||||||
pushed = false;
|
|
||||||
$('#testSuite').children().remove();
|
|
||||||
if (err && userTests.length > 0) {
|
|
||||||
userTests= [{text:"Program Execution Failure", err: "No user tests were run."}];
|
|
||||||
createTestDisplay();
|
|
||||||
} else if (userTests) {
|
|
||||||
userTests.push(false);
|
|
||||||
pushed = true;
|
|
||||||
userTests.forEach(function(test, ix, arr){
|
|
||||||
try {
|
|
||||||
if (test) {
|
|
||||||
console.log();
|
|
||||||
var output = eval(reassembleTest(test, data));
|
|
||||||
}
|
|
||||||
} catch(error) {
|
|
||||||
allTestsPassed = false;
|
|
||||||
arr[ix].err = error.name + ":" + error.message;
|
|
||||||
} finally {
|
|
||||||
if (!test) {
|
|
||||||
createTestDisplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (allTestsPassed) {
|
|
||||||
allTestsPassed = false;
|
|
||||||
showCompletion();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function showCompletion() {
|
|
||||||
$('#complete-courseware-dialog').modal('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
document.domain = 'localhost';
|
document.domain = 'localhost';
|
15
public/js/lib/coursewares/iFrameScripts.js
Normal file
15
public/js/lib/coursewares/iFrameScripts.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
(function() {
|
||||||
|
var allTestsGood = true;
|
||||||
|
var expect = chai.expect;
|
||||||
|
|
||||||
|
try {
|
||||||
|
eval(parent.allTests);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
allTestsGood = false;
|
||||||
|
} finally {
|
||||||
|
if (allTestsGood) {
|
||||||
|
parent.postMessage('CompleteAwesomeSauce', parent.nodeEnv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
@ -36,14 +36,6 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#complete-courseware-dialog').keydown(function(e) {
|
|
||||||
if (e.ctrlKey && e.keyCode == 13) {
|
|
||||||
$('.next-courseware-button').click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) {
|
function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) {
|
||||||
$('#complete-bonfire-dialog').modal('show');
|
$('#complete-bonfire-dialog').modal('show');
|
||||||
// Only post to server if there is an authenticated user
|
// Only post to server if there is an authenticated user
|
||||||
@ -74,6 +66,13 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#complete-bonfire-dialog').on('hidden.bs.modal', function() {
|
||||||
|
editor.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#complete-courseware-dialog').on('hidden.bs.modal', function() {
|
||||||
|
editor.focus();
|
||||||
|
});
|
||||||
$('.next-courseware-button').on('click', function() {
|
$('.next-courseware-button').on('click', function() {
|
||||||
if ($('.signup-btn-nav').length < 1) {
|
if ($('.signup-btn-nav').length < 1) {
|
||||||
$.post(
|
$.post(
|
||||||
|
@ -121,7 +121,7 @@ block content
|
|||||||
span.ion-close-circled
|
span.ion-close-circled
|
||||||
| Username not found
|
| Username not found
|
||||||
|
|
||||||
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-bonfire-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Take me to my next challenge
|
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-bonfire-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next bonfire (ctrl + enter)
|
||||||
|
|
||||||
|
|
||||||
- if (points && points > 2)
|
- if (points && points > 2)
|
||||||
|
@ -53,6 +53,7 @@ block content
|
|||||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||||
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
||||||
var bonfireName = 'Testing Courseware';
|
var bonfireName = 'Testing Courseware';
|
||||||
|
var prodOrDev = !{JSON.stringify(environment)};
|
||||||
.col-xs-12.col-sm-12.col-md-5.col-lg-6
|
.col-xs-12.col-sm-12.col-md-5.col-lg-6
|
||||||
#mainEditorPanel
|
#mainEditorPanel
|
||||||
form.code
|
form.code
|
||||||
@ -82,8 +83,4 @@ block content
|
|||||||
i.fa.fa-twitter
|
i.fa.fa-twitter
|
||||||
= phrase
|
= phrase
|
||||||
- else
|
- else
|
||||||
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
|
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user