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:
Michael Q Larson
2015-02-06 16:55:48 -08:00
parent 319b537e5b
commit 4f9474bc3a
9 changed files with 54 additions and 194 deletions

View File

@ -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!'

View File

@ -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()
}); });
}); });

View File

@ -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;
} }
}; };

View File

@ -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();
}
});
} }

View File

@ -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';

View 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);
}
}
})();

View File

@ -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(

View File

@ -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)

View File

@ -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 &nbsp; i.fa.fa-twitter &nbsp;
= 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