diff --git a/README.md b/README.md index 9770de3ebc2..0029a894e33 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Our campers (students) start by working through our free, self-paced, browser-ba 80% of our campers are over 25, and nearly a fifth of our campers are women. -This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Slack](http://freecodecamp.slack.com), a [blog](http://blog.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp). +This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [blog](http://blog.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp). [Join our community](http://www.freecodecamp.com/signin)! @@ -27,7 +27,7 @@ Contributing We welcome pull requests from Free Code Camp campers (our students) and seasoned JavaScript developers alike! Follow these steps to contribute: 1. Check our [public Waffle Board](https://waffle.io/freecodecamp/freecodecamp). -2. Pick an issue that nobody has claimed and start working on it. If your issue isn't on the board, open an issue. If you think you can fix it yourself, start working on it. Feel free to ask for help in our [Slack](http://freecodecamp.slack.com). +2. Pick an issue that nobody has claimed and start working on it. If your issue isn't on the board, open an issue. If you think you can fix it yourself, start working on it. Feel free to ask for help in our [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp) 3. Fork the project ([Need help with forking a project?](https://help.github.com/articles/fork-a-repo/)). You'll do all of your work on your forked copy. 4. Create a branch specific to the issue or feature you are working on. Push your work to that branch. ([Need help with branching?](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)) 5. Name the branch something like `user-xxx` where user is your username and xxx is the issue number you are addressing. diff --git a/common/models/user.json b/common/models/user.json index a7caad6227b..0254ff84075 100644 --- a/common/models/user.json +++ b/common/models/user.json @@ -134,7 +134,8 @@ "type": "string" }, "uncompletedBonfires": { - "type": "array" + "type": "array", + "default": [] }, "completedBonfires": { "type": [ diff --git a/config/secrets.js b/config/secrets.js index 2ea3cdef280..ed369d97665 100644 --- a/config/secrets.js +++ b/config/secrets.js @@ -13,10 +13,6 @@ module.exports = { key: process.env.BLOGGER_KEY }, - slack: { - key: process.env.SLACK_KEY - }, - mandrill: { user: process.env.MANDRILL_USER, password: process.env.MANDRILL_PASSWORD diff --git a/package.json b/package.json index 8213e9ac728..7fe7c38bd84 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "express-session": "~1.9.2", "express-validator": "~2.8.0", "font-awesome": "~4.3.0", - "forcedomain": "~0.4.0", "forever": "~0.14.1", "frameguard": "^0.2.2", "github-api": "~0.7.0", @@ -71,6 +70,7 @@ "node-slack": "0.0.7", "node-uuid": "^1.4.3", "nodemailer": "~1.3.0", + "object.assign": "^3.0.0", "passport-facebook": "^2.0.0", "passport-google-oauth2": "^0.1.6", "passport-linkedin-oauth2": "^1.2.1", diff --git a/pm2Start.js b/pm2Start.js new file mode 100644 index 00000000000..052f3bdbfa6 --- /dev/null +++ b/pm2Start.js @@ -0,0 +1,12 @@ +var pm2 = require('pm2'); +pm2.connect(function() { + pm2.start({ + name: 'server', + script: 'server/server.js', + exec_mode: 'cluster', + instances: '2', + max_memory_restart: '900M' + }, function(err, apps) { + pm2.disconnect(); + }); +}); diff --git a/public/js/calculator.js b/public/js/calculator.js index 8786b78bea2..9cd991a9e79 100644 --- a/public/js/calculator.js +++ b/public/js/calculator.js @@ -154,6 +154,10 @@ $(document).ready(function () { }, 1000); }); + d3.selectAll("#chart").on("click", function () { + change(); + }); + function change() { if ($("body").data("state") === "stacked") { transitionGrouped(); diff --git a/public/js/lib/coursewares/coursewaresJSFramework_0.0.5.js b/public/js/lib/coursewares/coursewaresJSFramework_0.0.6.js similarity index 57% rename from public/js/lib/coursewares/coursewaresJSFramework_0.0.5.js rename to public/js/lib/coursewares/coursewaresJSFramework_0.0.6.js index 2183c226d7d..ae7237ef5d0 100644 --- a/public/js/lib/coursewares/coursewaresJSFramework_0.0.5.js +++ b/public/js/lib/coursewares/coursewaresJSFramework_0.0.6.js @@ -1,3 +1,7 @@ +$(document).ready(function() { + $('#reset-button').on('click', resetEditor); +}); + var widgets = []; var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), { lineNumbers: true, @@ -18,7 +22,7 @@ editor.setSize("100%", "auto"); // Hijack tab key to enter two spaces intead editor.setOption("extraKeys", { Tab: function(cm) { - if (cm.somethingSelected()){ + if (cm.somethingSelected()) { cm.indentSelection("add"); } else { var spaces = Array(cm.getOption("indentUnit") + 1).join(" "); @@ -26,7 +30,7 @@ editor.setOption("extraKeys", { } }, "Shift-Tab": function(cm) { - if (cm.somethingSelected()){ + if (cm.somethingSelected()) { cm.indentSelection("subtract"); } else { var spaces = Array(cm.getOption("indentUnit") + 1).join(" "); @@ -40,12 +44,92 @@ editor.setOption("extraKeys", { }); +/* + Local Storage Update System By Andrew Cay(Resto) + codeStorage: singleton object that contains properties and methods related to + dealing with the localStorage system. + The keys work off of the variable challenge_name to make unique identifiers per bonfire + + Two extra functionalities: + Added anonymous version checking system incase of future updates to the system + Added keyup listener to editor(myCodeMirror) so the last update has been saved to storage +*/ +var codeStorage = { + version: 0.01, + keyVersion:"saveVersion", + keyValue: null,//where the value of the editor is saved + updateWait: 2000,// 2 seconds + updateTimeoutId: null, + eventArray: []//for firing saves +}; +// Returns true if the editor code was saved since last key press (use this if you want to make a "saved" notification somewhere") +codeStorage.hasSaved = function(){ + return ( updateTimeoutId === null ); +}; +codeStorage.onSave = function(func){ + codeStorage.eventArray.push(func); +}; +codeStorage.setSaveKey = function(key){ + codeStorage.keyValue = key + 'Val'; +}; +codeStorage.getEditorValue = function(){ + return ('' + localStorage.getItem(codeStorage.keyValue)); +}; + +codeStorage.isAlive = function() { + var val = this.getEditorValue() + return val !== 'null' && + val !== 'undefined' && + (val && val.length > 0); +} +codeStorage.updateStorage = function(){ + if(typeof(Storage) !== undefined) { + var value = editor.getValue(); + localStorage.setItem(codeStorage.keyValue, value); + } else { + var debugging = false; + if( debugging ){ + console.log('no web storage'); + } + } + codeStorage.updateTimeoutId = null; + codeStorage.eventArray.forEach(function(func){ + func(); + }); +}; +//Update Version +(function(){ + var savedVersion = localStorage.getItem('saveVersion'); + if( savedVersion === null ){ + localStorage.setItem(codeStorage.keyVersion, codeStorage.version);//just write current version + }else{ + if( savedVersion !== codeStorage.version ){ + //Update version + } + } +})(); + + + +///Set everything up one page +/// Update local save when editor has changed +codeStorage.setSaveKey(challenge_Name); +editor.on('keyup', function(){ + window.clearTimeout(codeStorage.updateTimeoutId); + codeStorage.updateTimeoutId = window.setTimeout(codeStorage.updateStorage, codeStorage.updateWait); +}); + var attempts = 0; if (attempts) { attempts = 0; } +var resetEditor = function resetEditor() { + editor.setValue(allSeeds); + codeStorage.updateStorage(); + +}; var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), { lineNumbers: false, @@ -61,7 +145,10 @@ codeOutput.setValue('/**\n' + ' */'); codeOutput.setSize("100%", "100%"); var info = editor.getScrollInfo(); -var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top; +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); @@ -71,20 +158,20 @@ var editorValue; var challengeSeed = challengeSeed || null; var tests = tests || []; + var allSeeds = ''; (function() { challengeSeed.forEach(function(elem) { - allSeeds += elem + '\n'; + allSeeds += elem + '\n'; }); })(); -editorValue = allSeeds; - +editorValue = (codeStorage.isAlive())? codeStorage.getEditorValue() : allSeeds; myCodeMirror.setValue(editorValue); -function doLinting () { - editor.operation(function () { +function doLinting() { + editor.operation(function() { for (var i = 0; i < widgets.length; ++i) editor.removeLineWidget(widgets[i]); widgets.length = 0; @@ -106,14 +193,14 @@ function doLinting () { }); }; -$('#submitButton').on('click', function () { +$('#submitButton').on('click', function() { bonfireExecute(); }); function bonfireExecute() { attempts++; - ga('send', 'event', 'Challenge', 'ran-code', challenge_Name); - userTests= null; + ga('send', 'event', 'Challenge', 'ran-code', challenge_Name); + userTests = null; $('#codeOutput').empty(); var userJavaScript = myCodeMirror.getValue(); userJavaScript = removeComments(userJavaScript); @@ -145,16 +232,23 @@ var scrapeTests = function(userJavaScript) { } var counter = 0; - var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/); + 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); + userJavaScript = userJavaScript.substring(0, match.index) + replacement + + userJavaScript.substring(match.index + match[0].length); if (!userTests) { - userTests= []; + userTests = []; } - userTests.push({"text": match[0], "line": counter, "err": null}); + userTests.push({ + "text": match[0], + "line": counter, + "err": null + }); counter++; match = regex.exec(userJavaScript); } @@ -176,17 +270,22 @@ var createTestDisplay = function() { if (pushed) { userTests.pop(); } - for (var i = 0; i < userTests.length;i++) { + 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("
" + test.text + "
" + test.err + "
") + .html( + "
" + + test.text + "
" + + test.err + "
") .appendTo($('#testSuite')); } else { $(testDoc) - .html("
" + test.text + "
") + .html( + "
" + + test.text + "
") .appendTo($('#testSuite')); } }; @@ -208,18 +307,21 @@ var runTests = function(err, data) { pushed = false; $('#testSuite').children().remove(); if (err && userTests.length > 0) { - userTests= [{text:"Program Execution Failure", err: "No user tests were run."}]; + userTests = [{ + text: "Program Execution Failure", + err: "No user tests were run." + }]; createTestDisplay(); } else if (userTests) { userTests.push(false); pushed = true; - userTests.forEach(function(chaiTestFromJSON, indexOfTestArray, __testArray){ + userTests.forEach(function(chaiTestFromJSON, indexOfTestArray, + __testArray) { try { if (chaiTestFromJSON) { var output = eval(reassembleTest(chaiTestFromJSON, data)); - debugger; } - } catch(error) { + } catch (error) { allTestsPassed = false; __testArray[indexOfTestArray].err = error.message; } finally { @@ -239,12 +341,12 @@ var runTests = function(err, data) { function showCompletion() { var time = Math.floor(Date.now()) - started; - ga('send', 'event', 'Challenge', 'solved', challenge_Name + ', Time: ' + time +', Attempts: ' + attempts); + ga('send', 'event', 'Challenge', 'solved', challenge_Name + ', Time: ' + time + + ', Attempts: ' + attempts); var bonfireSolution = myCodeMirror.getValue(); var didCompleteWith = $('#completed-with').val() || null; $.post( - '/completed-bonfire/', - { + '/completed-bonfire/', { challengeInfo: { challengeId: challenge_Id, challengeName: challenge_Name, @@ -252,10 +354,11 @@ function showCompletion() { challengeType: challengeType, solution: bonfireSolution } - }, function(res) { + }, + function(res) { if (res) { $('#complete-courseware-dialog').modal('show'); - $('#complete-courseware-dialog').keydown(function (e) { + $('#complete-courseware-dialog').keydown(function(e) { if (e.ctrlKey && e.keyCode == 13) { $('#next-courseware-button').click(); } diff --git a/public/js/main_0.0.2.js b/public/js/main_0.0.2.js index 65ec9f170c0..472fe7351dc 100644 --- a/public/js/main_0.0.2.js +++ b/public/js/main_0.0.2.js @@ -16,67 +16,11 @@ $(document).ready(function() { setCSRFToken($('meta[name="csrf-token"]').attr('content')); - $('#i-want-help').on('click', function() { - $('#help-modal').modal('hide'); - var editorValue = editor.getValue(); - var currentLocation = window.location.href; - $.post( - '/get-help', - { - payload: { - code: editorValue, - challenge: currentLocation - } - }, - function(res) { - if (res) { - window.open('https://freecodecamp.slack.com/messages/help/', '_blank') - } - } - ); - }); - - $('#i-want-help-editorless').on('click', function() { - $('#help-editorless-modal').modal('hide'); - var currentLocation = window.location.href; - $.post( - '/get-help', - { - payload: { - challenge: currentLocation - } - }, - function(res) { - if (res) { - window.open('https://freecodecamp.slack.com/messages/help/', '_blank') - } - } - ); - }); - $('#report-issue').on('click', function() { $('#issue-modal').modal('hide'); window.open('https://github.com/freecodecamp/freecodecamp/issues/new?&body=Challenge '+ window.location.href +' has an issue. Please describe how to reproduce it, and include links to screen shots if possible.', '_blank') }); - $('#i-want-to-pair').on('click', function() { - $('#pair-modal').modal('hide'); - var currentLocation = window.location.href; - $.post( - '/get-pair', - { - payload: { - challenge: currentLocation - } - }, - function(res) { - if (res) { - window.open('https://freecodecamp.slack.com/messages/letspair/', '_blank') - } - } - ); - }); - $('.checklist-element').each(function() { var checklistElementId = $(this).attr('id'); if(!!localStorage[checklistElementId]) { @@ -150,10 +94,6 @@ $(document).ready(function() { $('#help-modal').modal('show'); }); - $('#trigger-help-editorless-modal').on('click', function() { - $('#help-editorless-modal').modal('show'); - }); - $('#trigger-issue-modal').on('click', function() { $('#issue-modal').modal('show'); }); @@ -331,6 +271,7 @@ $(document).ready(function() { $('#story-submit').on('click', storySubmitButtonHandler); + var commentSubmitButtonHandler = function commentSubmitButtonHandler() { $('#comment-button').unbind('click'); var data = $('#comment-box').val(); diff --git a/seed/bonfireMDNlinks.js b/seed/bonfireMDNlinks.js index 9a9ea867417..bedd51b2dba 100644 --- a/seed/bonfireMDNlinks.js +++ b/seed/bonfireMDNlinks.js @@ -12,6 +12,7 @@ var links = "Currying": "https://leanpub.com/javascript-allonge/read#pabc", "Smallest Common Multiple": "https://www.mathsisfun.com/least-common-multiple.html", "Permutations": "https://www.mathsisfun.com/combinatorics/combinations-permutations.html", + "HTML Entities": "http://dev.w3.org/html5/html-author/charref", // ========= GLOBAL OBJECTS "Global Array Object" : "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", diff --git a/seed/challenges/advanced-bonfires.json b/seed/challenges/advanced-bonfires.json index e14504dba43..58f6602791a 100644 --- a/seed/challenges/advanced-bonfires.json +++ b/seed/challenges/advanced-bonfires.json @@ -81,7 +81,7 @@ "sym([1, 2, 3], [5, 2, 1, 4]);" ], "tests": [ - "expect(sym([1, 2, 3], [5, 2, 1, 4])).to.eqls([3, 5, 4])", + "expect(sym([1, 2, 3], [5, 2, 1, 4])).to.equal([3, 5, 4]);", "assert.deepEqual(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'should return the symmetric difference of the given arrays');", "assert.deepEqual(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'should return an array of unique values');", "assert.deepEqual(sym([1, 1]), [1], 'should return an array of unique values');" @@ -230,7 +230,7 @@ "permAlone('aab');" ], "tests": [ - "expect(permAlone('aab')).to.be.a.number;", + "expect(permAlone('aab')).to.be.a('number');", "expect(permAlone('aab')).to.equal(2);", "expect(permAlone('aaa')).to.equal(0);", "expect(permAlone('aabb')).to.equal(8);", diff --git a/seed/challenges/basic-bonfires.json b/seed/challenges/basic-bonfires.json index df4b6bc16c3..bc75adb4ac2 100644 --- a/seed/challenges/basic-bonfires.json +++ b/seed/challenges/basic-bonfires.json @@ -14,7 +14,7 @@ "Pair Programming is where two people code together on the same computer. It is an efficient way to collaborate, and widely practiced at software companies. Pair Programming is one of the core concepts of \"Agile\" Software Development, which you will hear more about later.", "Many people use Skype or Google Hangouts to pair program, but if you talk with professional software engineers, they will tell you that it's not really pair programming unless both people have the ability to use the keyboard and mouse.", "The most popular tool for pair programming is Screen Hero. You can download Screen Hero for Mac or Windows. Create your new user account from within the app.", - "We have a special chat room for people ready to pair program. Go to our http://freecodecamp.slack.com/messages/letspair and type \"Hello Pair Programmers!\"", + "We have a special chat room for people ready to pair program. Go to our LetsPair chatroom on gitter and type \"Hello Pair Programmers!\"", "If someone is available, they will be your \"pair\" - the person you pair programming with.", "If no one gets back to you in the first few minutes, don't worry. There will be lots of opportunities to pair program in the future.", "If someone does get back to you, private message them and ask for the email address they used to register Screen Hero.", @@ -180,7 +180,8 @@ "assert.deepEqual(palindrome(\"not a palindrome\"), false);", "assert.deepEqual(palindrome(\"A man, a plan, a canal. Panama\"), true);", "assert.deepEqual(palindrome(\"never odd or even\"), true);", - "assert.deepEqual(palindrome(\"nope\"), false);" + "assert.deepEqual(palindrome(\"nope\"), false);", + "assert.deepEqual(palindrome(\"almostomla\"), false);" ], "challengeSeed": [ "function palindrome(str) {", @@ -422,6 +423,7 @@ ], "tests": [ "expect(truncate('A-tisket a-tasket A green and yellow basket', 11)).to.eqls('A-tisket...');", + "expect(truncate('Peter Piper picked a peck of pickled peppers', 14)).to.eqls('Peter Piper...');", "assert(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length) === 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is = length');", "assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length + 2), 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is < length');" ], @@ -656,7 +658,10 @@ ], "tests": [ "assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');", - "assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');" + "assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');", + "assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1], 'should accept more than two additional arguments');", + "assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), [], 'should remove correct values from an array');", + "assert.deepEqual(destroyer(['tree', 'hamburger', 53], 'tree', 53), ['hamburger'], 'should handle NaN-elements');" ], "MDNlinks": [ "Arguments object", @@ -754,8 +759,8 @@ }, { "id": "a5de63ebea8dbee56860f4f2", - "name": "bonfire-diff-two-arrays", - "dashedName": "Bonfire: Diff Two Arrays", + "name": "Bonfire: Diff Two Arrays", + "dashedName": "bonfire-diff-two-arrays", "difficulty": "2.01", "description": [ "Compare two arrays and return a new array with any items not found in both of the original arrays.", @@ -853,7 +858,7 @@ "difficulty": "2.03", "description": [ "Perform a search and replace on the sentence using the arguments provided and return the new sentence.", - "First argument is the sentence the perform the search and replace on.", + "First argument is the sentence to perform the search and replace on.", "Second argument is the word that you will be replacing (before).", "Third argument is what you will be replacing the second argument with (after).", "NOTE: Preserve the case of the original word when you are replacing it. For example if you mean to replace the word 'Book' with the word 'dog', it should be replaced as 'Dog'", @@ -990,7 +995,8 @@ "expect(fearNotLetter('yz')).to.be.undefined;" ], "MDNlinks": [ - "String.charCodeAt()" + "String.charCodeAt()", + "String.fromCharCode()" ], "challengeType": 5, "nameCn": "", @@ -1091,7 +1097,7 @@ "dashedName": "bonfire-convert-html-entities", "difficulty": "2.07", "description": [ - "Convert the characters \"&\", \"<\", \">\", '\"', and \"'\", in a string to their corresponding HTML entities.", + "Convert the characters \"&\", \"<\", \">\", '\"' (double quote), and \"'\" (apostrophe), in a string to their corresponding HTML entities.", "Remember to use RSAP if you get stuck. Try to pair program. Write your own code." ], "challengeSeed": [ @@ -1104,10 +1110,16 @@ ], "tests": [ "assert.strictEqual(convert('Dolce & Gabbana'), 'Dolce & Gabbana', 'should escape characters');", + "assert.strictEqual(convert('Hamburgers < Pizza < Tacos'), 'Hamburgers < Pizza < Tacos', 'should escape characters');", + "assert.strictEqual(convert('Sixty > twelve'), 'Sixty > twelve', 'should escape characters');", + "assert.strictEqual(convert('Stuff in \"quotation marks\"'), 'Stuff in "quotation marks"', 'should escape characters');", + "assert.strictEqual(convert(\"Shindler's List\"), 'Shindler's List', 'should escape characters');", + "assert.strictEqual(convert('<>'), '<>', 'should escape characters');", "assert.strictEqual(convert('abc'), 'abc', 'should handle strings with nothing to escape');" ], "MDNlinks": [ - "RegExp" + "RegExp", + "HTML Entities" ], "challengeType": 5, "nameCn": "", diff --git a/seed/challenges/basic-html5-and-css.json b/seed/challenges/basic-html5-and-css.json index 4a8df44a719..7fdae6da097 100644 --- a/seed/challenges/basic-html5-and-css.json +++ b/seed/challenges/basic-html5-and-css.json @@ -943,7 +943,8 @@ "In addition to pixels, you can also specify a border-radius using a percentage." ], "tests": [ - "assert(parseInt($('img').css('border-top-left-radius')) > 48, 'Your image should have a border radius of 50 percent, making it perfectly circular.')" + "assert(parseInt($('img').css('border-top-left-radius')) > 48, 'Your image should have a border radius of 50 percent, making it perfectly circular.')", + "assert(editor.match(/50%/g), 'Be sure to use a percentage instead of a pixel value.')" ], "challengeSeed": [ "", @@ -1005,7 +1006,7 @@ ], "tests": [ "assert((/cat photos/gi).test($('a').text()), 'Your a element should have the anchor text of \"cat photos\"')", - "assert($('a').filter(function(index) { return /com/gi.test($('a').attr('href')); }).length > 0, 'You need an a element that links to http://catphotoapp.com.')", + "assert(/http:\\/\\/catphotoapp\\.com/gi.test($('a').attr('href')), 'You need an a element that links to http://catphotoapp.com.')", "assert(editor.match(/<\\/a>/g) && editor.match(/<\\/a>/g).length === editor.match(/a element has a closing tag.')" ], "challengeSeed": [ @@ -1540,7 +1541,7 @@ ], "tests": [ "assert($('input[placeholder]').length > 0, 'Add a placeholder attribute text input element.')", - "assert($('input').attr('placeholder').match(/cat\\s+photo\\s+URL/gi), 'Set the value of your placeholder attribute to \"cat photo URL\".')" + "assert($('input') && $('input').attr('placeholder') && $('input').attr('placeholder').match(/cat\\s+photo\\s+URL/gi), 'Set the value of your placeholder attribute to \"cat photo URL\".')" ], "challengeSeed": [ "", @@ -1613,7 +1614,7 @@ "For example: <form action=\"/url-where-you-want-to-submit-form-data\"></form>." ], "tests": [ - "assert($('form').length > 0, 'Wrap your text input element within a form element.')", + "assert($('form') && $('form').children('input') && $('form').children('input').length > 0, 'Wrap your text input element within a form element.')", "assert($('form').attr('action'), 'Your form element should have an action attribute.')", "assert(editor.match(/<\\/form>/g) && editor.match(/
/g).length === editor.match(/form element has a closing tag.')", "assert(editor.match(/\\/submit-cat-photo/ig), 'Make sure your form action is set to /submit-cat-photo.')" diff --git a/seed/challenges/bootstrap.json b/seed/challenges/bootstrap.json index eeac669f73b..41a72297316 100644 --- a/seed/challenges/bootstrap.json +++ b/seed/challenges/bootstrap.json @@ -626,7 +626,7 @@ "The \"row\" class is applied to a div, and the buttons themselves can be wrapped within it." ], "tests": [ - "assert($('div.row:has(button)'), 'Your buttons should all be wrapped within the same div element with the class \"row\".')", + "assert($('div.row:has(button)').length > 0, 'Your buttons should all be wrapped within the same div element with the class \"row\".')", "assert($('div.col-xs-4:has(button)').length > 2, 'Each of your Bootstrap buttons should be wrapped within its own a div element with the class \"col-xs-4\".')", "assert(editor.match(/<\\/button>/g) && editor.match(/