diff --git a/README.md b/README.md index 9b0c87d631..91176090b0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,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 [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), 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://medium.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp). [Join our community here](http://www.freecodecamp.com/signin). diff --git a/client/commonFramework.js b/client/commonFramework.js index bff815cb1d..cfbb3141e4 100644 --- a/client/commonFramework.js +++ b/client/commonFramework.js @@ -1,31 +1,72 @@ -// common namespace -// all classes should be stored here -var common = common || { - // init is an array of functions that are - // called at the beginning of dom ready - init: [] -}; +var common = (function() { + // common namespace + // all classes should be stored here + var common = window.common || { + // init is an array of functions that are + // called at the beginning of dom ready + init: [] + }; -common.challengeName = common.challengeName || window.challenge_Name ? - window.challenge_Name : - ''; + common.challengeName = common.challengeName || window.challenge_Name ? + window.challenge_Name : + ''; -common.challengeType = common.challengeType || window.challengeType ? - window.challengeType : - 0; + common.challengeType = common.challengeType || window.challengeType ? + window.challengeType : + 0; -common.challengeId = common.challengeId || window.challenge_Id; + common.challengeId = common.challengeId || window.challenge_Id; -common.challengeSeed = common.challengeSeed || window.challengeSeed ? - window.challengeSeed : - []; + common.challengeSeed = common.challengeSeed || window.challengeSeed ? + window.challengeSeed : + []; -common.seed = common.challengeSeed.reduce(function(seed, line) { - return seed + line + '\n'; -}, ''); + common.seed = common.challengeSeed.reduce(function(seed, line) { + return seed + line + '\n'; + }, ''); + + common.replaceScriptTags = function replaceScriptTags(value) { + return value + .replace(/'); + }; + + common.replaceFormActionAttr = function replaceFormAction(value) { + return value.replace(/]*>/, function(val) { + return val.replace(/action(\s*?)=/, 'fccfaa$1='); + }); + }; + + common.replaceFccfaaAttr = function replaceFccfaaAttr(value) { + return value.replace(/]*>/, function(val) { + return val.replace(/fccfaa(\s*?)=/, 'action$1='); + }); + }; + + return common; +})(); // store code in the URL common.codeUri = (function(common, encode, decode, location, history) { + var replaceScriptTags = common.replaceScriptTags; + var replaceSafeTags = common.replaceSafeTags; + var replaceFormActionAttr = common.replaceFormActionAttr; + var replaceFccfaaAttr = common.replaceFccfaaAttr; + + function encodeFcc(val) { + return replaceScriptTags(replaceFormActionAttr(val)); + } + + function decodeFcc(val) { + return replaceSafeTags(replaceFccfaaAttr(val)); + } + var codeUri = { encode: function(code) { return encode(code); @@ -54,10 +95,14 @@ common.codeUri = (function(common, encode, decode, location, history) { }, false); }, isAlive: function() { - return codeUri.isInQuery(location.search) || + return codeUri.enabled && + codeUri.isInQuery(location.search) || codeUri.isInQuery(location.hash); }, parse: function() { + if (!codeUri.enabled) { + return null; + } var query; if (location.search && codeUri.isInQuery(location.search)) { query = location.search.replace(/^\?/, ''); @@ -67,7 +112,7 @@ common.codeUri = (function(common, encode, decode, location, history) { null, location.href.split('?')[0] ); - location.hash = '#?' + query; + location.hash = '#?' + encodeFcc(query); } } else { query = location.hash.replace(/^\#\?/, ''); @@ -82,15 +127,21 @@ common.codeUri = (function(common, encode, decode, location, history) { var key = param.split('=')[0]; var value = param.split('=')[1]; if (key === 'solution') { - return codeUri.decode(value); + return decodeFcc(codeUri.decode(value || '')); } return solution; }, null); }, querify: function(solution) { - location.hash = '?solution=' + codeUri.encode(solution); + if (!codeUri.enabled) { + return null; + } + location.hash = '?solution=' + + codeUri.encode(encodeFcc(solution)); + return solution; - } + }, + enabled: true }; common.init.push(function() { @@ -306,12 +357,6 @@ var sandBox = (function(jailed, codeOutput) { return sandBox; }(window.jailed, common.codeOutput)); -function replaceSafeTags(value) { - return value - .replace(/fccss/gi, ''); -} - var BDDregex = new RegExp( '(expect(\\s+)?\\(.*\\;)|' + '(assert(\\s+)?\\(.*\\;)|' + @@ -408,7 +453,6 @@ var editor = (function(CodeMirror, emmetCodeMirror, common) { common.init.push(function() { var editorValue; if (common.codeUri.isAlive()) { - console.log('in query'); editorValue = common.codeUri.parse(); } else { editorValue = codeStorage.isAlive() ? @@ -416,7 +460,7 @@ var editor = (function(CodeMirror, emmetCodeMirror, common) { common.seed; } - editor.setValue(replaceSafeTags(editorValue)); + editor.setValue(common.replaceSafeTags(editorValue)); editor.refresh(); }); @@ -445,6 +489,7 @@ function workerError(error) { var housing = $('#testSuite'); if (display.html() !== error) { display.remove(); + housing.prepend( '
' + error.replace(/j\$/gi, '$').replace(/jdocument/gi, 'document').replace(/jjQuery/gi, 'jQuery') + @@ -471,7 +516,10 @@ function safeHTMLRun(test) { var codeStorage = common.codeStorage; if (common.challengeType === '0') { var previewFrame = document.getElementById('preview'); - var preview = previewFrame.contentDocument || previewFrame.contentWindow.document; + + var preview = previewFrame.contentDocument || + previewFrame.contentWindow.document; + if (editor.getValue().match(/\/gi) !== null) { var s = editor .getValue() @@ -554,9 +602,11 @@ function updatePreview() { if (typeof prodOrDev !== 'undefined') { - var nodeEnv = prodOrDev === 'production' ? + /* eslint-disable no-unused-vars */ + var nodeEnv = window.prodOrDev === 'production' ? 'http://www.freecodecamp.com' : 'http://localhost:3001'; + /* eslint-enable no-unused-vars */ if (common.challengeType === '0') { setTimeout(updatePreview, 300); @@ -567,8 +617,11 @@ if (typeof prodOrDev !== 'undefined') { * "post" methods */ +/* eslint-disable no-unused-vars */ var testResults = []; var postSuccess = function(data) { +/* eslint-enable no-unused-vars */ + var testDoc = document.createElement('div'); $(testDoc).html( "
" + @@ -614,7 +667,9 @@ function showCompletion() { isInitRun = false; return; } - var time = Math.floor(Date.now()) - started; + + var time = Math.floor(Date.now()) - window.started; + ga( 'send', 'event', @@ -672,8 +727,11 @@ function showCompletion() { }); } +/* eslint-disable no-unused-vars */ var resetEditor = function resetEditor() { - editor.setValue(replaceSafeTags(common.seed)); +/* eslint-enable no-unused-vars */ + + editor.setValue(common.replaceSafeTags(common.seed)); $('#testSuite').empty(); bonfireExecute(true); common.codeStorage.updateStorage(); @@ -863,15 +921,15 @@ common.init.push((function() { var nextStep = getNextStep($(stepClass)); $(this) .parent() - .addClass('animated fadeOutLeft') - .delay(700) + .addClass('animated fadeOutLeft fast-animation') + .delay(250) .queue(function(next) { $(this).addClass('hidden'); if (nextStep) { $(nextStep) .removeClass('hidden') - .addClass('animated slideInRight') - .delay(1000) + .addClass('animated slideInRight fast-animation') + .delay(500) .queue(function(next) { $(this).removeClass('slideInRight'); next(); diff --git a/client/less/chat.less b/client/less/chat.less new file mode 100644 index 0000000000..a6f83171ca --- /dev/null +++ b/client/less/chat.less @@ -0,0 +1,24 @@ +.chat-embed-main-title { + display: flex; + flex-grow: 1; + padding-left: 31px; + padding-top: 7px; +} + +.gitter-chat-embed { + z-index: 100; + position: fixed; + + top: 0; + left: 60%; + bottom: 0; + right: 0; + + display: flex; + flex-direction: row; + transition: transform 0.3s cubic-bezier(0.16, 0.22, 0.22, 1.7); +} + +.gitter-chat-embed.is-collapsed:not(.is-loading) { + transform: translateX(110%); +} diff --git a/client/less/main.less b/client/less/main.less index 067290e9be..aa70867894 100644 --- a/client/less/main.less +++ b/client/less/main.less @@ -96,6 +96,10 @@ h1, h2, h3, h4, h5, h6, p, li { margin-right: 5px; } +.fa:hover { + text-decoration: none; +} + .img-center { margin: 0 auto; } @@ -490,11 +494,17 @@ thead { border-radius: 5px; } +.story-section { + height: 500px; +} + .testimonial-copy { - font-size: 20px; - text-align: center; + text-align: justify; + font-size: 18px !important; + margin-left: 20px; + margin-right: 20px; @media (min-width: 991px) and (max-width: 1199px) { - height: 120px; + height: 140px; } @media (min-width: 1200px) { height: 90px; @@ -945,6 +955,11 @@ code { margin: 0!important; } +// gitter chat +.gitter-chat-embed { + z-index: 20000 !important; +} + //uncomment this to see the dimensions of all elements outlined in red //* { // border-color: red; @@ -1052,3 +1067,5 @@ code { transform: rotate(0deg); } } + +@import "chat.less"; diff --git a/client/main.js b/client/main.js index c1578c1d6f..6f147abcf7 100644 --- a/client/main.js +++ b/client/main.js @@ -1,12 +1,120 @@ -var mapShareKey = 'map-shares'; +var main = window.main || {}; + +main.mapShareKey = 'map-shares'; + +main.ga = window.ga || function() {}; + +main = (function(main) { + + // should be set before gitter script loads + ((window.gitter = {}).chat = {}).options = { + disableDefaultChat: true + }; + // wait for sidecar to load + + main.chat = {}; + main.chat.isOpen = false; + main.chat.createHelpChat = function createHelpChat() { + throw new Error('Sidecar chat has not initialized'); + }; + + document.addEventListener('gitter-sidecar-ready', function(e) { + main.chat.GitterChat = e.detail.Chat; + + main.chat.createHelpChat = function(room, helpChatBtnClass, roomTitle) { + roomTitle = roomTitle || 'Waypoint Help'; + + $('body').append( + '