diff --git a/bower.json b/bower.json index ad1dbf82ea..b43360485a 100644 --- a/bower.json +++ b/bower.json @@ -2,10 +2,6 @@ "name": "freecodecamp", "version": "0.0.0", "homepage": "http://freecodecamp.com", - "authors": [ - "Quincy Larson " - ], - "license": "MIT", "private": true, "ignore": [ "**/.*", @@ -16,15 +12,12 @@ "tests" ], "dependencies": { - "angular-ui-bootstrap": "~0.13.0", - "angular": "~1.3.15", "d3": "~3.5.5", "jquery": "~2.1.4", "cal-heatmap": "~3.5.2", "bootstrap": "~3.3.4", "font-awesome": "~4.3.0", "moment": "~2.10.2", - "angular-bootstrap": "~0.13.0", "jshint": "~2.9.0", "lightbox2": "~2.8.1", "rxjs": "~4.0.6", diff --git a/client/commonFramework/phone-scroll-lock.js b/client/commonFramework/phone-scroll-lock.js index bf5af55c4f..a9b58fb23c 100644 --- a/client/commonFramework/phone-scroll-lock.js +++ b/client/commonFramework/phone-scroll-lock.js @@ -11,7 +11,7 @@ window.common = (function({ common = { init: [] }}) { if (magiVal < 0) { magiVal = 0; } - $('.editorScrollDiv').css('height', magiVal - 85 + 'px'); + $('.editorScrollDiv').css('height', magiVal - 50 + 'px'); } magiVal = $(window).height() - $('.navbar').height(); @@ -22,7 +22,7 @@ window.common = (function({ common = { init: [] }}) { $('.scroll-locker') .css('min-height', $('.editorScrollDiv').height()) - .css('height', magiVal - 185); + .css('height', magiVal - 50); } else { $('.editorScrollDiv').css('max-height', 500 + 'px'); @@ -30,7 +30,7 @@ window.common = (function({ common = { init: [] }}) { .css('position', 'inherit') .css('top', 'inherit') .css('width', '100%') - .css('max-height', '85%'); + .css('max-height', '100%'); } }; diff --git a/client/main.js b/client/main.js index 50e4449d85..99beae1720 100644 --- a/client/main.js +++ b/client/main.js @@ -190,6 +190,10 @@ $(document).ready(function() { var storySubmitButtonHandler = function storySubmitButtonHandler() { + if (!$('#story-submission-form')[0].checkValidity()) { + return null; + } + var link = $('#story-url').val(); var headline = $('#story-title').val(); var description = $('#description-box').val(); @@ -252,154 +256,3 @@ $(document).ready(function() { window.location.href = link; }); }); - -var profileValidation = - window.angular.module('profileValidation', ['ui.bootstrap']); - -profileValidation.controller( - 'profileValidationController', - [ - '$scope', - '$http', - function($scope, $http) { - $http.get('/account/api').success(function(data) { - $scope.user = data.user; - - $scope.user.username = $scope.user.username ? - $scope.user.username.toLowerCase() : - null; - - $scope.storedUsername = data.user.username; - $scope.storedEmail = data.user.email; - $scope.user.email = $scope.user.email ? - $scope.user.email.toLowerCase() : - null; - - $scope.user.twitterHandle = $scope.user.twitterHandle ? - $scope.user.twitterHandle.toLowerCase() : - null; - - $scope.asyncComplete = true; - }); - } - ] -); - -profileValidation.controller( - 'pairedWithController', - [ - '$scope', - function($scope) { $scope.existingUser = null; } - ] -); - -profileValidation.controller('emailSignUpController', function() {}); - -profileValidation.controller('emailSignInController', function() {}); - -profileValidation.controller('URLSubmitController', function() {}); - -profileValidation.controller('nonprofitFormController', function() {}); - -profileValidation.controller( - 'doneWithFirst100HoursFormController', - function() {} -); - -profileValidation.controller('submitStoryController', function() {}); - -profileValidation.directive( - 'uniqueUsername', - [ - '$http', - function($http) { - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, element, attrs, ngModel) { - - element.bind('keyup', function() { - - ngModel.$setValidity('unique', true); - var username = element.val(); - if (username) { - var config = { params: { username: username } }; - $http - .get('/api/users/exists', config) - .success(function(result) { - if (username === scope.storedUsername) { - ngModel.$setValidity('unique', true); - } else if (result.exists) { - ngModel.$setValidity('unique', false); - } - }); - } - }); - } - }; - } - ] -); - -profileValidation.directive('existingUsername', - [ - '$http', - function($http) { - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, element, attrs, ngModel) { - - element.bind('keyup', function() { - - if (element.val().length > 0) { - ngModel.$setValidity('exists', false); - } else { - element.removeClass('ng-dirty'); - ngModel.$setPristine(); - } - - var username = element.val(); - if (username) { - var config = { params: { username: username } }; - $http - .get('/api/users/exists', config) - .success(function(result) { - ngModel.$setValidity('exists', result.exists); - }); - } - }); - } - }; - }]); - -profileValidation.directive( - 'uniqueEmail', - [ - '$http', - function($http) { - return { - restrict: 'A', - require: 'ngModel', - link: function getUnique(scope, element, attrs, ngModel) { - element.bind('keyup', function() { - ngModel.$setValidity('unique', true); - var email = element.val(); - if (email) { - var config = { params: { email: email } }; - $http - .get('/api/users/exists', config) - .success(function(result) { - if (email === scope.storedEmail) { - ngModel.$setValidity('unique', true); - } else if (result.exists) { - ngModel.$setValidity('unique', false); - } - }); - } - }); - } - }; - } - ] -); diff --git a/common/models/user.js b/common/models/user.js index bb746ed8d8..f2e49ae252 100644 --- a/common/models/user.js +++ b/common/models/user.js @@ -164,7 +164,7 @@ module.exports = function(User) { req.flash('errors', { msg: 'Invalid username or password.' }); - return res.redirect('/'); + return res.redirect('/email-signin'); }); User.afterRemote('logout', function(ctx, result, next) { diff --git a/gulpfile.js b/gulpfile.js index b58517ee9d..b1e28b9c0f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -93,9 +93,6 @@ var paths = { vendorMain: [ 'public/bower_components/jquery/dist/jquery.min.js', 'public/bower_components/bootstrap/dist/js/bootstrap.min.js', - 'public/bower_components/angular/angular.min.js', - 'public/bower_components/angular-bootstrap/ui-bootstrap.min.js', - 'public/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js', 'public/bower_components/d3/d3.min.js', 'public/bower_components/moment/min/moment.min.js', 'public/bower_components/lightbox2/dist/js/lightbox.min.js', diff --git a/server/boot/challenge.js b/server/boot/challenge.js index ca316bc97e..df2e2bf5bf 100644 --- a/server/boot/challenge.js +++ b/server/boot/challenge.js @@ -285,7 +285,7 @@ module.exports = function(app) { origChallengeName + '` Please double check the name.' }); - return Observable.just('/challenges'); + return Observable.just('/map'); } if (dasherize(challenge.name) !== origChallengeName) { diff --git a/server/views/account/email-signin.jade b/server/views/account/email-signin.jade index b1c3fa4b46..e36d19b97b 100644 --- a/server/views/account/email-signin.jade +++ b/server/views/account/email-signin.jade @@ -1,27 +1,19 @@ extends ../layout block content - .jumbotron.text-center(ng-controller="emailSignInController") - h2 Sign in with an email address here: - form(method='POST', action='/api/users/login') - input(type='hidden', name='_csrf', value=_csrf) - .col-sm-6.col-sm-offset-3 - .form-group - input.form-control(type='email', name='email', id='email', placeholder='Email', ng-model='email', autofocus=true) - | {{ $scope.email }} - .form-group - input.form-control(type='password', name='password', id='password', placeholder='Password', ng-model='password') - .form-group - button.btn.btn-primary(type='submit') - span.ion-android-hand - | Login - span    - a.btn.btn-info(href='/forgot') Forgot your password? - br - br - br - br - br - br - br - br - br + .jumbotron.text-center + .row + .col-xs-12 + h2 Sign in with an email address here: + .col-sm-6.col-sm-offset-3 + form(method='POST', action='/api/users/login') + input(type='hidden', name='_csrf', value=_csrf) + .form-group + input.input-lg.form-control(type='email', name='email', id='email', placeholder='Email', autofocus=true) + .form-group + input.input-lg.form-control(type='password', name='password', id='password', placeholder='Password') + button.btn.btn-primary.btn-lg.btn-block(type='submit') + span.ion-android-hand + | Login + .button-spacer + .button-spacer + a.btn.btn-info.btn-lg.btn-block(href='/forgot') Forgot your password? diff --git a/server/views/account/email-signup.jade b/server/views/account/email-signup.jade index 965eca605e..15ab666565 100644 --- a/server/views/account/email-signup.jade +++ b/server/views/account/email-signup.jade @@ -1,51 +1,18 @@ extends ../layout block content + script. + var challengeName = 'Email Signup' .jumbotron.text-center h2 Sign up with an email address here: - form.form-horizontal(method='POST', action='/api/users', name="signupForm", novalidate="novalidate") - input(type='hidden', name='_csrf', value=_csrf) - .form-group - .col-sm-6.col-sm-offset-3 - input.form-control(type='email', ng-model='email', ng-keypress='', name='email', id='email', placeholder='email', autofocus, required, autocomplete="off", unique-email='') - .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.email.$error.required && !signupForm.email.$pristine") - alert(type='danger') - span.ion-close-circled - | Your email address is required. - .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.$error.email && !signupForm.email.$pristine") - alert(type='danger') - span.ion-close-circled - | Please enter a valid email format. - .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.email.$error.unique && !signupForm.email.$pristine") - alert(type='danger') - span.ion-close-circled - | That email address is already in use. - .form-group - .col-sm-6.col-sm-offset-3 - input.form-control(type='password', ng-model='password', name='password', id='password', placeholder='password', required, ng-minlength=8) - .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.password.$error.minlength && !signupForm.password.$pristine") - alert(type='danger') - span.ion-close-circled - | Your password must be at least 8 characters long. - .form-group - .col-sm-6.col-sm-offset-3 - input.form-control(type='password', ng-model='confirmPassword', name='confirmPassword', id='confirmPassword', placeholder='confirm password', required, ng-minlength=5) - .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="(confirmPassword !== password) && !signupForm.confirmPassword.$pristine") - alert(type='danger') - span.ion-close-circled - | Passwords must match. - .form-group - .col-sm-6.col-sm-offset-3 - button.btn.btn-success(type='submit', ng-disabled='signupForm.$invalid') - span.ion-person-add - | Signup - br - br - br - br - br - br - br - br - br - script. - var challengeName = 'Email Signup' + form.form-horizontal(method='POST', action='/api/users', name="signupForm") + .row + .col-sm-6.col-sm-offset-3 + input(type='hidden', name='_csrf', value=_csrf) + .form-group + input.input-lg.form-control(type='email', name='email', id='email', placeholder='email', autofocus, required, autocomplete="off") + .form-group + input.input-lg.form-control(type='password', name='password', id='password', placeholder='password', required, pattern=".{8,50}", title="Must be at least 8 characters and no longer than 50 characters.") + .form-group + button.btn.btn-lg.btn-success.btn-block(type='submit') + span.ion-person-add + | Signup diff --git a/server/views/account/forgot.jade b/server/views/account/forgot.jade index 14527a4f27..c5da16558c 100644 --- a/server/views/account/forgot.jade +++ b/server/views/account/forgot.jade @@ -3,14 +3,13 @@ extends ../layout block content .col-sm-8.col-sm-offset-2.jumbotron form(method='POST', action="/forgot") - h1 Forgot Password + h2.text-center Forgot Password Reset input(type='hidden', name='_csrf', value=_csrf) .form-group - p Enter your email address below and we will send you password reset instructions. - label.control-label(for='email') Email - input.form-control(type='email', name='email', id='email', placeholder='Email', autofocus=true) + p Enter your email address. We'll send you password reset instructions. + input.form-control.input-lg(type='email', name='email', id='email', placeholder='Email', autofocus=true required) .form-group - button.btn.btn-primary(type='submit') + button.btn.btn-primary.btn-lg.btn-block(type='submit') i.fa.fa-key | Reset Password diff --git a/server/views/account/signin.jade b/server/views/account/signin.jade index b42f56935b..e6a01f3cee 100644 --- a/server/views/account/signin.jade +++ b/server/views/account/signin.jade @@ -22,3 +22,4 @@ block content a(href="/email-signup") Or sign up using your email address here. p a(href="/email-signin") If you originally signed up using your email address, you can sign in here. + diff --git a/server/views/coursewares/showBonfire.jade b/server/views/coursewares/showBonfire.jade index 3357573bee..41c16da1f5 100644 --- a/server/views/coursewares/showBonfire.jade +++ b/server/views/coursewares/showBonfire.jade @@ -5,7 +5,7 @@ block content link(rel='stylesheet', href='/bower_components/CodeMirror/theme/monokai.css') link(rel='stylesheet', href='/css/ubuntu.css') - .row(ng-controller="pairedWithController") + .row .col-md-4.col-lg-3 .scroll-locker(id = "scroll-locker") .innerMarginFix(style=' width: 99%') @@ -24,16 +24,6 @@ block content ul: li: a(href=""+link, target="_blank") !{MDNkeys[index]} if (user) - form.form-horizontal(novalidate='novalidate', name='completedWithForm') - .form-group.text-center.negative-10 - .col-xs-12 - // extra field to distract password tools like lastpass from injecting css into our username field - input.form-control(ng-show="false") - input.form-control#completed-with(name="existingUser", placeholder="Your pair's username if pairing", existing-username='', ng-model="existingUser") - .col-xs-12(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0") - alert(type='danger') - span.ion-close-circled - | Username not found label.negative-10.btn.btn-primary.btn-block.btn-lg#submitButton i.fa.fa-play |   Run tests (ctrl + enter) diff --git a/server/views/coursewares/showJS.jade b/server/views/coursewares/showJS.jade index f630881d16..3b4c1131b4 100644 --- a/server/views/coursewares/showJS.jade +++ b/server/views/coursewares/showJS.jade @@ -4,7 +4,7 @@ block content link(rel='stylesheet', href='/bower_components/CodeMirror/addon/lint/lint.css') link(rel='stylesheet', href='/bower_components/CodeMirror/theme/monokai.css') link(rel='stylesheet', href='/css/ubuntu.css') - .row(ng-controller="pairedWithController") + .row .col-md-4.col-lg-3 .scroll-locker(id = "scroll-locker") .innerMarginFix(style = "width: 99%;") diff --git a/server/views/coursewares/showVideo.jade b/server/views/coursewares/showVideo.jade index 2368076288..df8d00dc92 100644 --- a/server/views/coursewares/showVideo.jade +++ b/server/views/coursewares/showVideo.jade @@ -44,7 +44,7 @@ block content .modal-content .modal-header.challenge-list-header= compliment a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - .modal-body(ng-controller="pairedWithController") + .modal-body .text-center .animated.zoomInDown span.completion-icon.ion-checkmark-circled.text-primary diff --git a/server/views/coursewares/showZiplineOrBasejump.jade b/server/views/coursewares/showZiplineOrBasejump.jade index f4936aed74..5debac73ab 100644 --- a/server/views/coursewares/showZiplineOrBasejump.jade +++ b/server/views/coursewares/showZiplineOrBasejump.jade @@ -43,30 +43,24 @@ block content .modal-content .modal-header.challenge-list-header= compliment a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - .modal-body(ng-controller="pairedWithController") + .modal-body .text-center .animated.zoomInDown span.completion-icon.ion-checkmark-circled.text-primary if (user) - form.form-horizontal(novalidate='novalidate', name='completedWithForm') + form.form-horizontal(name='completedWithForm', id='basejump-or-zipline-submit-form') .form-group.text-center .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2 // extra field to distract password tools like lastpass from injecting css into our username field - input.form-control(ng-show="false") + input.form-control.hidden if (challengeType === "3") - input.form-control#public-url(type='url', name="solutionUrl", placeholder="http://codepen.io/your-pen-here", autofocus, required, ng-minlength="10", ng-model="deploymentUrl") + input.form-control#public-url(type="url", name="solutionUrl", placeholder="http://codepen.io/your-pen-here", autofocus, required) else - input.form-control#public-url(type='url', name="solutionUrl", placeholder="http://yourapp.com", autofocus, required, ng-minlength="10", ng-model="deploymentUrl") - input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project", ng-model="githubUrl") - - input.form-control#completed-with(name="existingUser", ng-minlength placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser") - .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0") - alert(type='danger') - span.ion-close-circled - | Username not found + input.form-control#public-url(type="url", name="solutionUrl", placeholder="http://yourapp.com", autofocus, required) + input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project") if (user) - a.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid') Go to my next challenge + a.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf) Go to my next challenge .button-spacer else a.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) Go to my next challenge diff --git a/server/views/layout-wide.jade b/server/views/layout-wide.jade index 2996712464..df33c7b4aa 100644 --- a/server/views/layout-wide.jade +++ b/server/views/layout-wide.jade @@ -1,5 +1,5 @@ doctype html -html(ng-app='profileValidation', lang='en') +html(lang='en') head include partials/meta include partials/stylesheets diff --git a/server/views/layout.jade b/server/views/layout.jade index 5c23b7361e..f64024fdf9 100644 --- a/server/views/layout.jade +++ b/server/views/layout.jade @@ -1,5 +1,5 @@ doctype html -html(ng-app='profileValidation', lang='en') +html(lang='en') head include partials/meta include partials/stylesheets diff --git a/server/views/stories/preliminary-submit.jade b/server/views/stories/preliminary-submit.jade index 082f27cec5..0855f741e8 100644 --- a/server/views/stories/preliminary-submit.jade +++ b/server/views/stories/preliminary-submit.jade @@ -1,53 +1,53 @@ .col-xs-12 - div(ng-controller="URLSubmitController") - form.input-group(name='URLSubmit') - input#story-url.big-text-field.field-responsive.form-control(placeholder='Paste your link here', name='link', type='url', ng-model='possibleURL', required='required', autofocus) - span.input-group-btn - button#preliminary-story-submit.btn.btn-big.btn-primary.btn-responsive(type='button', ng-disabled='URLSubmit.link.$invalid') Submit - div(ng-show="URLSubmit.link.$error.url && !URLsubmit.link.$pristine") - alert(type='danger') - span.ion-close-circled - | Please enter a valid URL format (http://www.example.com/). + div + form.input-group(id='URLSubmit' name='URLSubmit') + input#story-url.big-text-field.field-responsive.form-control(placeholder='Paste your link here', name='link', type='url', required, autofocus) + span.input-group-btn + button#preliminary-story-submit.btn.btn-big.btn-primary.btn-responsive(type='submit') Submit .spacer script. - $('#story-url').on('keypress', function(e) { - if (e.which === 13 || e === 13) { - $('#preliminary-story-submit').click(); - } - }); - var preliminaryStorySubmit = function preliminaryStorySubmit() { + $('#story-url').on('keypress', function(e) { + if (e.keyCode === 13) { + $('#preliminary-story-submit').click(); + } + }); + function preliminaryStorySubmit(e) { + if (!$('#URLSubmit')[0].checkValidity()) { + return null; + } + e.preventDefault(); - var storyURL = $('#story-url').val(); - $('#preliminary-story-submit').attr('disabled', 'disabled'); + var storyURL = $('#story-url').val(); + $('#preliminary-story-submit').attr('disabled', 'disabled'); - $.post('/stories/preliminary', - { - data: { - url: storyURL - } - }) - .fail(function (xhr, textStatus, errorThrown) { - $('#preliminary-story-submit').attr('disabled', false); - }) - .done(function (data, textStatus, xhr) { - if (data.alreadyPosted) { - window.location = data.storyURL; - } else { - window.location = '/stories/submit/new-story?url=' + - encodeURIComponent(data.storyURL) + - '&title=' + encodeURIComponent(data.storyTitle) + - '&image=' + encodeURIComponent(data.storyImage) + - '&description=' + encodeURIComponent(data.storyMetaDescription); - } - }); - } - $('#preliminary-story-submit').on('click', preliminaryStorySubmit); + $.post('/stories/preliminary', + { + data: { + url: storyURL + } + }) + .fail(function (xhr, textStatus, errorThrown) { + $('#preliminary-story-submit').attr('disabled', false); + }) + .done(function (data, textStatus, xhr) { + if (data.alreadyPosted) { + window.location = data.storyURL; + } else { + window.location = '/stories/submit/new-story?url=' + + encodeURIComponent(data.storyURL) + + '&title=' + encodeURIComponent(data.storyTitle) + + '&image=' + encodeURIComponent(data.storyImage) + + '&description=' + encodeURIComponent(data.storyMetaDescription); + } + }); + } + $('#preliminary-story-submit').on('click', preliminaryStorySubmit); - arr = $( "h3 input:checked" ) - .map(function() { - return this.id; - }) - .get() - .join('&'); + arr = $( "h3 input:checked" ) + .map(function() { + return this.id; + }) + .get() + .join('&'); diff --git a/server/views/stories/submit-story.jade b/server/views/stories/submit-story.jade index 71b36b3e9c..52409cda62 100644 --- a/server/views/stories/submit-story.jade +++ b/server/views/stories/submit-story.jade @@ -13,17 +13,12 @@ .col-xs-12.col-md-1 label.control-label.control-label-story-submission(for='name') Link .col-xs-12.col-md-11 - input#story-url.form-control(name='Link', ng-model='submitStory.url', disabled="disabled", ng-init='submitStory.url="#{storyURL}"') + input#story-url.form-control(name='Link', disabled, value='#{storyURL}') .form-group .col-xs-12.col-md-1 label.control-label.control-label-story-submission(for='name') Title .col-xs-12.col-md-11 - - input#story-title.form-control(placeholder='Type a headline for your link here', name='Title', maxlength='90' ng-model='submitStory.title',required='required', autocomplete="off", ng-init='submitStory.title="#{storyTitle}"' autofocus) - .col-xs-12.col-md-11.col-md-offset-1(ng-cloak, ng-show="submitStory.title.$error.required") - alert(type='danger') - span.ion-close-circled - | A headline is required to submit. + input#story-title.form-control(value='#{storyTitle}', name='Title', maxlength='90', autocomplete="off", autofocus, required) .form-group .col-xs-12.col-md-offset-1 span.pull-left#textarea_feedback @@ -40,10 +35,8 @@ .row .form-group - button.btn.btn-big.btn-block.btn-primary#story-submit(type='submit', ng-disabled='submitStory.$invalid || !submitStory') Submit + button.btn.btn-big.btn-block.btn-primary#story-submit(type='submit') Submit script. - $('#story-url').val(storyURL).attr('disabled', 'disabled'); - $('#story-title').val(storyTitle); - if (storyImage) { - $('#image-display').removeClass('hidden-element'); - } + if (main.storyImage) { + $('#image-display').removeClass('hidden-element'); + }