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) {
|
||||
console.log(req.user.points)
|
||||
if (req.user.points >= 53) {
|
||||
res.render('contact/done-with-first-100-hours', {
|
||||
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(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewareHash: courseware._id
|
||||
|
||||
coursewareHash: courseware._id,
|
||||
environment: resources.whichEnvironment()
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -247,6 +247,9 @@ module.exports = {
|
||||
.map(function(elem) {
|
||||
return elem.name;
|
||||
});
|
||||
},
|
||||
whichEnvironment: function() {
|
||||
return process.env.NODE_ENV;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -10,13 +10,7 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor")
|
||||
scrollbarStyle: 'null',
|
||||
lineWrapping: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
onKeyEvent: doLinting,
|
||||
extraKeys : {
|
||||
"Ctrl-Enter" : function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
onKeyEvent: doLinting
|
||||
});
|
||||
var editor = myCodeMirror;
|
||||
editor.setSize("100%", "auto");
|
||||
@ -26,6 +20,10 @@ editor.setOption("extraKeys", {
|
||||
Tab: function(cm) {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
},
|
||||
"Ctrl-Enter": function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -59,6 +57,7 @@ var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"),
|
||||
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' +
|
||||
@ -243,4 +242,9 @@ function showCompletion() {
|
||||
console.log(time);
|
||||
ga('send', 'event', 'Bonfire', 'solved', bonfireName + ', Time: ' + time +', Attempts: ' + attempts);
|
||||
$('#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',
|
||||
lineWrapping: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
onKeyEvent: doLinting,
|
||||
extraKeys : {
|
||||
"Ctrl-Enter" : function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
onKeyEvent: doLinting
|
||||
});
|
||||
var editor = myCodeMirror;
|
||||
|
||||
@ -30,6 +24,10 @@ editor.setOption("extraKeys", {
|
||||
Tab: function(cm) {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
},
|
||||
"Ctrl-Enter": function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -52,20 +50,7 @@ var allTests = '';
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
|
||||
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 otherTestsForNow = "<script src='/js/lib/coursewares/iFrameScripts.js'></script>";
|
||||
|
||||
var delay;
|
||||
// Initialize CodeMirror editor with a nice html5 canvas demo.
|
||||
@ -73,12 +58,12 @@ editor.on("change", function () {
|
||||
clearTimeout(delay);
|
||||
delay = setTimeout(updatePreview, 300);
|
||||
});
|
||||
|
||||
var nodeEnv = prodOrDev === 'production' ? 'http://www.freecodecamp.com' : 'http://localhost:3001';
|
||||
function updatePreview() {
|
||||
var previewFrame = document.getElementById('preview');
|
||||
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
|
||||
preview.open();
|
||||
preview.write(libraryIncludes + editor.getValue() + coursewareTests);
|
||||
preview.write(libraryIncludes + editor.getValue() + otherTestsForNow);
|
||||
preview.close();
|
||||
}
|
||||
setTimeout(updatePreview, 300);
|
||||
@ -97,28 +82,6 @@ eventer(messageEvent,function(e) {
|
||||
}
|
||||
},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 tests = tests || [];
|
||||
var allSeeds = '';
|
||||
@ -128,7 +91,6 @@ var allSeeds = '';
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
myCodeMirror.setValue(allSeeds);
|
||||
|
||||
function doLinting () {
|
||||
@ -154,133 +116,14 @@ function doLinting () {
|
||||
});
|
||||
};
|
||||
|
||||
$('#submitButton').on('click', function () {
|
||||
bonfireExecute();
|
||||
});
|
||||
|
||||
function bonfireExecute() {
|
||||
userTests= null;
|
||||
$('#codeOutput').empty();
|
||||
var userJavaScript = myCodeMirror.getValue();
|
||||
userJavaScript = removeComments(userJavaScript);
|
||||
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);
|
||||
function showCompletion() {
|
||||
$('#complete-courseware-dialog').modal('show');
|
||||
$('#complete-courseware-dialog').keydown(function(e) {
|
||||
if (e.ctrlKey && e.keyCode == 13) {
|
||||
$('.next-courseware-button').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
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';
|
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) {
|
||||
$('#complete-bonfire-dialog').modal('show');
|
||||
// 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() {
|
||||
if ($('.signup-btn-nav').length < 1) {
|
||||
$.post(
|
||||
|
@ -121,7 +121,7 @@ block content
|
||||
span.ion-close-circled
|
||||
| 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)
|
||||
|
@ -53,6 +53,7 @@ block content
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
||||
var bonfireName = 'Testing Courseware';
|
||||
var prodOrDev = !{JSON.stringify(environment)};
|
||||
.col-xs-12.col-sm-12.col-md-5.col-lg-6
|
||||
#mainEditorPanel
|
||||
form.code
|
||||
@ -82,8 +83,4 @@ block content
|
||||
i.fa.fa-twitter
|
||||
= phrase
|
||||
- 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