Merge branch 'master' into ramda-fire

This commit is contained in:
Nathan Leniz
2015-02-16 00:51:11 -05:00
32 changed files with 5485 additions and 1073 deletions

View File

@@ -73,11 +73,10 @@ var editorValue;
var challengeSeed = challengeSeed || null;
var tests = tests || [];
var challengeEntryPoint = challengeEntryPoint || null;
if (challengeSeed !== null) {
editorValue = challengeSeed + '\n\n' + challengeEntryPoint;
editorValue = challengeSeed;
} else {
editorValue = nonChallengeValue;
}
@@ -121,9 +120,7 @@ function bonfireExecute() {
userJavaScript = removeComments(userJavaScript);
userJavaScript = scrapeTests(userJavaScript);
// simple fix in case the user forgets to invoke their function
if (challengeEntryPoint && challengeSeed) {
userJavaScript = challengeEntryPoint + ' ' + userJavaScript;
}
submit(userJavaScript, function(cls, message) {
if (cls) {
codeOutput.setValue(message.error);

View File

@@ -26,7 +26,6 @@ editor.setOption("extraKeys", {
cm.replaceSelection(spaces);
},
"Ctrl-Enter": function() {
bonfireExecute();
return false;
}
});
@@ -40,7 +39,8 @@ var libraryIncludes = "<script src='//ajax.googleapis.com/ajax/libs/jquery/2.1.3
"<link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.min.css'/>" +
"<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css'/>" +
"<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css'/>" +
"<style>body { padding: 0px 3px 0px 3px; }</style>";
"<style>body { padding: 0px 3px 0px 3px; }</style>" +
"<script>var expect = chai.expect; var should = chai.should(); var assert = chai.assert;</script>";
var allTests = '';
(function() {
@@ -59,28 +59,42 @@ editor.on("change", function () {
});
var nodeEnv = prodOrDev === 'production' ? 'http://www.freecodecamp.com' : 'http://localhost:3001';
function updatePreview() {
goodTests = 0;
var previewFrame = document.getElementById('preview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
$('#testSuite').empty();
preview.write(libraryIncludes + editor.getValue() + otherTestsForNow);
preview.close();
}
setTimeout(updatePreview, 300);
/**
* Window postMessage receiving funtionality
* "post" methods
*/
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to message from child window
eventer(messageEvent,function(e) {
if (e.data === 'CompleteAwesomeSauce') {
var postSuccess = function(data) {
var testDoc = document.createElement("div");
$(testDoc)
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-checkmark-circled big-success-icon'></i></div><div class='col-xs-10 test-output test-vertical-center wrappable'>" + JSON.parse(data) + "</div></div><div class='ten-pixel-break'/>")
.appendTo($('#testSuite'));
testSuccess();
};
var postError = function(data) {
var testDoc = document.createElement("div");
$(testDoc)
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-close-circled big-error-icon'></i></div><div class='col-xs-10 test-output wrappable'>" + JSON.parse(data) + "</div></div><div class='ten-pixel-break'/>")
.prependTo($('#testSuite'))
};
var goodTests = 0;
var testSuccess = function() {
goodTests++;
if (goodTests === tests.length) {
showCompletion();
}
},false);
};
var challengeSeed = challengeSeed || null;
var tests = tests || [];
var allSeeds = '';
@@ -115,14 +129,18 @@ function doLinting () {
});
};
//$('#testSuite').empty();
function showCompletion() {
var time = Math.floor(Date.now() / 1000) - started;
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time);
$('#complete-courseware-dialog').modal('show');
$('#complete-courseware-dialog').keydown(function(e) {
$('#next-courseware-button').removeAttr('disabled');
$('#next-courseware-button').addClass('animated tada');
if (!userLoggedIn) {
$('#complete-courseware-dialog').modal('show');
}
$('body').keydown(function(e) {
if (e.ctrlKey && e.keyCode == 13) {
$('.next-courseware-button').click();
$('#next-courseware-button').click();
}
});
}

View File

@@ -0,0 +1,234 @@
var widgets = [];
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), {
lineNumbers: true,
mode: "javascript",
theme: 'monokai',
runnable: true,
lint: true,
matchBrackets: true,
autoCloseBrackets: true,
scrollbarStyle: 'null',
lineWrapping: true,
gutters: ["CodeMirror-lint-markers"],
onKeyEvent: doLinting
});
var editor = myCodeMirror;
editor.setSize("100%", "auto");
// Hijack tab key to enter two spaces intead
editor.setOption("extraKeys", {
Tab: function(cm) {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
cm.replaceSelection(spaces);
},
"Ctrl-Enter": function() {
bonfireExecute();
return false;
}
});
var attempts = 0;
if (attempts) {
attempts = 0;
}
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 = '';
(function() {
challengeSeed.forEach(function(elem) {
allSeeds += elem + '\n';
});
})();
editorValue = allSeeds;
myCodeMirror.setValue(editorValue);
function doLinting () {
editor.operation(function () {
for (var i = 0; i < widgets.length; ++i)
editor.removeLineWidget(widgets[i]);
widgets.length = 0;
JSHINT(editor.getValue());
for (var i = 0; i < JSHINT.errors.length; ++i) {
var err = JSHINT.errors[i];
if (!err) continue;
var msg = document.createElement("div");
var icon = msg.appendChild(document.createElement("span"));
icon.innerHTML = "!!";
icon.className = "lint-error-icon";
msg.appendChild(document.createTextNode(err.reason));
msg.className = "lint-error";
widgets.push(editor.addLineWidget(err.line - 1, msg, {
coverGutter: false,
noHScroll: true
}));
}
});
};
$('#submitButton').on('click', function () {
bonfireExecute();
});
function bonfireExecute() {
attempts++;
ga('send', 'event', 'Challenge', 'ran-code', challengeName);
userTests= null;
$('#codeOutput').empty();
var userJavaScript = myCodeMirror.getValue();
userJavaScript = removeComments(userJavaScript);
userJavaScript = scrapeTests(userJavaScript);
// simple fix in case the user forgets to invoke their function
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) {
console.log('Should be displaying bad tests');
$(testDoc)
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-close-circled big-error-icon'></i></div><div class='col-xs-10 test-output wrappable'>" + test.text + "</div><div class='col-xs-10 test-output wrappable'>" + test.err + "</div></div><div class='ten-pixel-break'/>")
.prependTo($('#testSuite'))
} else {
$(testDoc)
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-checkmark-circled big-success-icon'></i></div><div class='col-xs-10 test-output test-vertical-center wrappable'>" + test.text + "</div></div><div class='ten-pixel-break'/>")
.appendTo($('#testSuite'));
}
};
};
var expect = chai.expect;
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) {
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() {
var time = Math.floor(Date.now() / 1000) - started;
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time +', Attempts: ' + attempts);
$('#complete-courseware-dialog').modal('show');
$('#complete-courseware-dialog').keydown(function(e) {
if (e.ctrlKey && e.keyCode == 13) {
$('.next-bonfire-button').click();
}
});
}

View File

@@ -1,14 +1,19 @@
(function() {
var allTestsGood = true;
var expect = chai.expect;
var tests = parent.tests;
try {
eval(parent.allTests);
} catch (err) {
allTestsGood = false;
} finally {
if (allTestsGood) {
parent.postMessage('CompleteAwesomeSauce', parent.nodeEnv);
for (var i = 0; i < tests.length; i++) {
var thisTest = true;
try {
eval(parent.tests[i]);
} catch (err) {
allTestsGood = false;
thisTest = false;
parent.postError(JSON.stringify(tests[i]));
} finally {
if (thisTest) {
parent.postSuccess(JSON.stringify(tests[i]));
}
}
}
})();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
/**
* Created by jason on 2/11/15.
*/
function nextSession () {
var next = 'Our next session will be ';
var today = moment().day(moment().day());
if (today > moment().day(2)) {
next += moment().day(9).format('dddd, MMMM Do YYYY') + ' at 9PM EST!';
} else {
next += moment().day('Tuesday').format('dddd, MMMM Do YYYY') + ' at 9PM EST!';
}
return next;
}

View File

@@ -66,6 +66,9 @@ $(document).ready(function() {
completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash);
});
$('#completed-courseware').on('click', function() {
$('#complete-courseware-dialog').modal('show');
});
$('#complete-bonfire-dialog').on('hidden.bs.modal', function() {
editor.focus();
@@ -74,7 +77,7 @@ $(document).ready(function() {
$('#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) {
$.post(
'/completed-courseware',
@@ -164,7 +167,7 @@ profileValidation.controller('doneWithFirst100HoursFormController', ['$scope',
}
]);
profileValidation.directive('uniqueUsername', function($http) {
profileValidation.directive('uniqueUsername',['$http',function($http) {
return {
restrict: 'A',
require: 'ngModel',
@@ -183,9 +186,9 @@ profileValidation.directive('uniqueUsername', function($http) {
});
}
}
});
}]);
profileValidation.directive('existingUsername', function($http) {
profileValidation.directive('existingUsername', ['$http', function($http) {
return {
restrict: 'A',
require: 'ngModel',
@@ -194,27 +197,26 @@ profileValidation.directive('existingUsername', function($http) {
if (element.val().length > 0) {
ngModel.$setValidity('exists', false);
} else {
element.removeClass('ng-dirty');
ngModel.$setPristine();
}
if (element.val()) {
$http.get("/api/checkExistingUsername/" + element.val()).success(function (data) {
if (element.val() == scope.existingUsername) {
ngModel.$setValidity('exists', false);
} else if (data) {
ngModel.$setValidity('exists', true);
}
$http
.get("/api/checkExistingUsername/" + element.val())
.success(function (data) {
ngModel.$setValidity('exists', data);
});
}
});
}
}
});
}]);
profileValidation.directive('uniqueEmail', function($http) {
profileValidation.directive('uniqueEmail', ['$http', function($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
link: function getUnique (scope, element, attrs, ngModel) {
element.bind("keyup", function (event) {
ngModel.$setValidity('unique', true);
if (element.val()) {
@@ -229,4 +231,4 @@ profileValidation.directive('uniqueEmail', function($http) {
});
}
}
});
}]);