Cleaning up angular, preparing to make new editor framework for coursewares

pull/82/head
Nathan Leniz 2015-02-02 20:39:05 -05:00
parent f059bc33d8
commit a558777382
3 changed files with 235 additions and 3 deletions

View File

@ -0,0 +1,232 @@
/**
* Created by nathanleniz on 2/2/15.
*/
var widgets = [];
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), {
lineNumbers: true,
mode: "html-mixed",
theme: 'monokai',
runnable: true,
lint: true,
matchBrackets: true,
autoCloseBrackets: true,
scrollbarStyle: 'null',
lineWrapping: true,
gutters: ["CodeMirror-lint-markers"],
onKeyEvent: doLinting,
extraKeys : {
"Ctrl-Enter" : function() {
bonfireExecute();
return false;
}
}
});
var editor = myCodeMirror;
editor.setSize("100%", "auto");
// Default value for editor if one isn't provided in (i.e. a challenge)
var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByte replacement.\n' +
'Please feel free to use Bonfire as an in-browser playground and linting tool.\n' +
'Note that you can also write tests using Chai.js by using the keywords assert and expect */\n\n' +
'function test() {\n' +
' assert(2 !== 3, "2 is not equal to 3");\n' +
' return [1,2,3].map(function(elem) {\n' +
' return elem * elem;\n' +
' });\n' +
'}\n' +
'expect(test()).to.be.a("array");\n\n' +
'assert.deepEqual(test(), [1,4,9]);\n\n' +
'var foo = test();\n' +
'foo.should.be.a("array");\n\n' +
'test();\n';
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 challengeEntryPoint = challengeEntryPoint || null;
if (challengeSeed !== null) {
editorValue = challengeSeed + '\n\n' + challengeEntryPoint;
} else {
editorValue = nonChallengeValue;
}
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() {
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
if (challengeEntryPoint) {
userJavaScript = challengeEntryPoint + ' ' + 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-bonfire-dialog').modal('show');
}

View File

@ -158,7 +158,7 @@ profileValidation.directive('uniqueUsername', function($http) {
} }
} }
}); });
// TODO: FIX THIS
profileValidation.directive('existingUsername', function($http) { profileValidation.directive('existingUsername', function($http) {
return { return {
restrict: 'A', restrict: 'A',
@ -171,7 +171,7 @@ profileValidation.directive('existingUsername', function($http) {
ngModel.$setPristine(); ngModel.$setPristine();
} }
if (element.val()) { if (element.val()) {
$http.get("/api/checkExistingUsername/" + element.val() + ' ').success(function (data) { $http.get("/api/checkExistingUsername/" + element.val()).success(function (data) {
if (element.val() == scope.existingUsername) { if (element.val() == scope.existingUsername) {
ngModel.$setValidity('exists', false); ngModel.$setValidity('exists', false);
} else if (data) { } else if (data) {

View File

@ -59,7 +59,7 @@
"difficulty": "1.03", "difficulty": "1.03",
"description": [ "description": [
"Return 'true' if a given string is a palindrome.", "Return 'true' if a given string is a palindrome.",
"A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation and case.", "A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.",
"You'll need to remove punctuation and turn everything lower case in order to check for palindromes.", "You'll need to remove punctuation and turn everything lower case in order to check for palindromes.",
"We'll pass strings with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.", "We'll pass strings with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.",
"Return true if the string is a palindrome. Otherwise, return false." "Return true if the string is a palindrome. Otherwise, return false."