From 4f9474bc3a06570bf8292de33d92837f3df1fc79 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Fri, 6 Feb 2015 16:55:48 -0800 Subject: [PATCH] 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. --- controllers/contact.js | 1 - controllers/courseware.js | 4 +- controllers/resources.js | 3 + public/js/lib/bonfire/bonfireFramework.js | 18 +- .../lib/coursewares/coursewaresFramework.js | 183 ++---------------- public/js/lib/coursewares/iFrameScripts.js | 15 ++ public/js/main.js | 15 +- views/bonfire/show.jade | 2 +- views/coursewares/show.jade | 7 +- 9 files changed, 54 insertions(+), 194 deletions(-) create mode 100644 public/js/lib/coursewares/iFrameScripts.js diff --git a/controllers/contact.js b/controllers/contact.js index 3eef484786..1a959936c1 100644 --- a/controllers/contact.js +++ b/controllers/contact.js @@ -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!' diff --git a/controllers/courseware.js b/controllers/courseware.js index 716e7d00d2..c5efb1cdc4 100644 --- a/controllers/courseware.js +++ b/controllers/courseware.js @@ -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() }); }); diff --git a/controllers/resources.js b/controllers/resources.js index 9887cc7979..56234fe8e2 100644 --- a/controllers/resources.js +++ b/controllers/resources.js @@ -247,6 +247,9 @@ module.exports = { .map(function(elem) { return elem.name; }); + }, + whichEnvironment: function() { + return process.env.NODE_ENV; } }; diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index b807263ac7..7dcbae9d31 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -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(); + } + }); } \ No newline at end of file diff --git a/public/js/lib/coursewares/coursewaresFramework.js b/public/js/lib/coursewares/coursewaresFramework.js index 51b9481901..11ed28c9e6 100644 --- a/public/js/lib/coursewares/coursewaresFramework.js +++ b/public/js/lib/coursewares/coursewaresFramework.js @@ -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 = ""; +var otherTestsForNow = ""; 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("
" + test.text + "
" + test.err + "
") - .prependTo($('#testSuite')) - } else { - $(testDoc) - .html("
" + test.text + "
") - .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'; \ No newline at end of file diff --git a/public/js/lib/coursewares/iFrameScripts.js b/public/js/lib/coursewares/iFrameScripts.js new file mode 100644 index 0000000000..32a9c504b9 --- /dev/null +++ b/public/js/lib/coursewares/iFrameScripts.js @@ -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); + } + } +})(); \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index ea9921d4a7..fb73269169 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -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( diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index 04cf0e76e6..086ba767e0 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -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) diff --git a/views/coursewares/show.jade b/views/coursewares/show.jade index 93ebb3e468..72765c44de 100644 --- a/views/coursewares/show.jade +++ b/views/coursewares/show.jade @@ -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 - - - - \ No newline at end of file + a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress \ No newline at end of file