diff options
author | Dennis Eriksen <dennis.se@gmail.com> | 2013-03-20 12:43:33 +0100 |
---|---|---|
committer | Dennis Eriksen <dennis.se@gmail.com> | 2013-03-20 12:43:33 +0100 |
commit | 266767e6b31d4799b218a7dc9ffd0d6f2eca92a8 (patch) | |
tree | e3e68b3acdfb276cadcc23d0028a6c1dd3bc8f21 | |
parent | Edited "Sign in" button - for fun (diff) | |
download | Divid-266767e6b31d4799b218a7dc9ffd0d6f2eca92a8.tar.gz |
login screen
-rw-r--r-- | public/css/login.css | 138 | ||||
-rw-r--r-- | public/js/controllers/homeController.js | 67 | ||||
-rw-r--r-- | public/js/controllers/loginController.js | 14 | ||||
-rw-r--r-- | public/js/controllers/signupController.js | 9 | ||||
-rw-r--r-- | public/js/form-validators/accountValidator.js | 80 | ||||
-rw-r--r-- | public/js/form-validators/emailValidator.js | 39 | ||||
-rw-r--r-- | public/js/form-validators/loginValidator.js | 29 | ||||
-rw-r--r-- | public/js/form-validators/resetValidator.js | 37 | ||||
-rw-r--r-- | public/js/views/home.js | 49 | ||||
-rw-r--r-- | public/js/views/login.js | 51 | ||||
-rw-r--r-- | public/js/views/reset.js | 27 | ||||
-rw-r--r-- | public/js/views/signup.js | 39 | ||||
-rw-r--r-- | views/login.ejs | 63 |
13 files changed, 631 insertions, 11 deletions
diff --git a/public/css/login.css b/public/css/login.css new file mode 100644 index 0000000..5709783 --- /dev/null +++ b/public/css/login.css @@ -0,0 +1,138 @@ +body { + margin: 0; + padding: 0; + height: 100%; + background: #f2f9fe; + background: -moz-radial-gradient(center, ellipse cover, #f2f9fe 0%, #d6f0fd 100%); +/* FF3.6+ */ + background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, #f2f9fe), color-stop(100%, #d6f0fd)); +/* Chrome,Safari4+ */ + background: -webkit-radial-gradient(center, ellipse cover, #f2f9fe 0%, #d6f0fd 100%); +/* Chrome10+,Safari5.1+ */ + background: -o-radial-gradient(center, ellipse cover, #f2f9fe 0%, #d6f0fd 100%); +/* Opera 12+ */ + background: -ms-radial-gradient(center, ellipse cover, #f2f9fe 0%, #d6f0fd 100%); +/* IE10+ */ + background: radial-gradient(center, ellipse cover, #f2f9fe 0%, #d6f0fd 100%); +/* W3C */ +} +#login-container { + width: 340px; + margin: 160px auto; +} +#login-container label { + margin: 15px 0 5px 5px; +} +#login-container button { + width: 150px; + padding: 6px 40px 6px 40px; + float: left; + margin-top: 15px; +} +#login-container .checkbox { + margin: 23px 0 0 180px; +} +#login-container .btm-links { + text-align: center; + margin-top: 10px; +} +#login-container #create-account { + float: right; + margin-right: 13px; +} +#login-container #forgot-password { + float: left; + margin-left: 10px; +} +#account-form-container { + width: 460px; + margin: 100px auto; +} +#country-list { + width: 280px; +} +.modal-form-errors li { + color: #808080; + text-shadow: -1px 1px 0 #fff; + -moz-text-shadow: -1px 1px 0 #fff; + -webkit-text-shadow: -1px 1px 0 #fff; + color: #d8000c; +} +.modal-single-input { + width: 452px; + margin: -200px 0 0 -232px; +} +.modal-single-input form { + color: #808080; + text-shadow: -1px 1px 0 #fff; + -moz-text-shadow: -1px 1px 0 #fff; + -webkit-text-shadow: -1px 1px 0 #fff; + margin-bottom: 0; +} +.modal-single-input form button { + width: 80px; + top: 213px; + position: absolute; +} +.modal-single-input form #cancel { + right: 110px; +} +.modal-single-input form #submit { + right: 18px; +} +.modal-single-input .modal-body { + height: 140px; + overflow: hidden; + padding-bottom: 0; +} +.modal-single-input .modal-footer { + height: 20px; +} +.modal-alert { + width: 310px; + margin: -200px 0 0 -150px; +} +#btn-logout { + width: 100px; + top: 1px; + right: 8px; + position: absolute; +} +#print { + padding: 20px; +} +#four04 { + padding: 20px; +} +.clear-fix { + clear: both; +} +.well { + margin-left: 0; + border: 1px solid #ccc; +} +.form-horizontal .control-label { + width: 80px; +} +.form-horizontal .controls { + margin-left: 120px; +} +.form-horizontal .form-actions { + padding: 17px 0 0 270px; +} +label { + color: #808080; + text-shadow: -1px 1px 0 #fff; + -moz-text-shadow: -1px 1px 0 #fff; + -webkit-text-shadow: -1px 1px 0 #fff; +} +.subheading { + color: #808080; + text-shadow: -1px 1px 0 #fff; + -moz-text-shadow: -1px 1px 0 #fff; + -webkit-text-shadow: -1px 1px 0 #fff; + margin-top: 3px; +} +button i { + padding-left: 8px; +} diff --git a/public/js/controllers/homeController.js b/public/js/controllers/homeController.js new file mode 100644 index 0000000..9894d0e --- /dev/null +++ b/public/js/controllers/homeController.js @@ -0,0 +1,67 @@ + +function HomeController() +{ + +// bind event listeners to button clicks // + var that = this; + +// handle user logout // + $('#btn-logout').click(function(){ that.attemptLogout(); }); + +// confirm account deletion // + $('#account-form-btn1').click(function(){$('.modal-confirm').modal('show')}); + +// handle account deletion // + $('.modal-confirm .submit').click(function(){ that.deleteAccount(); }); + + this.deleteAccount = function() + { + $('.modal-confirm').modal('hide'); + var that = this; + $.ajax({ + url: '/delete', + type: 'POST', + data: { id: $('#userId').val()}, + success: function(data){ + that.showLockedAlert('Your account has been deleted.<br>Redirecting you back to the homepage.'); + }, + error: function(jqXHR){ + console.log(jqXHR.responseText+' :: '+jqXHR.statusText); + } + }); + } + + this.attemptLogout = function() + { + var that = this; + $.ajax({ + url: "/home", + type: "POST", + data: {logout : true}, + success: function(data){ + that.showLockedAlert('You are now logged out.<br>Redirecting you back to the homepage.'); + }, + error: function(jqXHR){ + console.log(jqXHR.responseText+' :: '+jqXHR.statusText); + } + }); + } + + this.showLockedAlert = function(msg){ + $('.modal-alert').modal({ show : false, keyboard : false, backdrop : 'static' }); + $('.modal-alert .modal-header h3').text('Success!'); + $('.modal-alert .modal-body p').html(msg); + $('.modal-alert').modal('show'); + $('.modal-alert button').click(function(){window.location.href = '/';}) + setTimeout(function(){window.location.href = '/';}, 3000); + } +} + +HomeController.prototype.onUpdateSuccess = function() +{ + $('.modal-alert').modal({ show : false, keyboard : true, backdrop : true }); + $('.modal-alert .modal-header h3').text('Success!'); + $('.modal-alert .modal-body p').html('Your account has been updated.'); + $('.modal-alert').modal('show'); + $('.modal-alert button').off('click'); +} diff --git a/public/js/controllers/loginController.js b/public/js/controllers/loginController.js new file mode 100644 index 0000000..a894aed --- /dev/null +++ b/public/js/controllers/loginController.js @@ -0,0 +1,14 @@ + +function LoginController() +{ + +// bind event listeners to button clicks // + + $('#login-form #forgot-password').click(function(){ $('#get-credentials').modal('show');}); + +// automatically toggle focus between the email modal window and the login form // + + $('#get-credentials').on('shown', function(){ $('#email-tf').focus(); }); + $('#get-credentials').on('hidden', function(){ $('#user-tf').focus(); }); + +}
\ No newline at end of file diff --git a/public/js/controllers/signupController.js b/public/js/controllers/signupController.js new file mode 100644 index 0000000..97d20e6 --- /dev/null +++ b/public/js/controllers/signupController.js @@ -0,0 +1,9 @@ + +function SignupController() +{ +// redirect to homepage when cancel button is clicked // + $('#account-form-btn1').click(function(){ window.location.href = '/';}); + +// redirect to homepage on new account creation, add short delay so user can read alert window // + $('.modal-alert #ok').click(function(){ setTimeout(function(){window.location.href = '/';}, 300)}); +}
\ No newline at end of file diff --git a/public/js/form-validators/accountValidator.js b/public/js/form-validators/accountValidator.js new file mode 100644 index 0000000..6de2dfc --- /dev/null +++ b/public/js/form-validators/accountValidator.js @@ -0,0 +1,80 @@ + +function AccountValidator(){ + +// build array maps of the form inputs & control groups // + + this.formFields = [$('#name-tf'), $('#email-tf'), $('#user-tf'), $('#pass-tf')]; + this.controlGroups = [$('#name-cg'), $('#email-cg'), $('#user-cg'), $('#pass-cg')]; + +// bind the form-error modal window to this controller to display any errors // + + this.alert = $('.modal-form-errors'); + this.alert.modal({ show : false, keyboard : true, backdrop : true}); + + this.validateName = function(s) + { + return s.length >= 3; + } + + this.validatePassword = function(s) + { + // if user is logged in and hasn't changed their password, return ok + if ($('#userId').val() && s===''){ + return true; + } else{ + return s.length >= 6; + } + } + + this.validateEmail = function(e) + { + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(e); + } + + this.showErrors = function(a) + { + $('.modal-form-errors .modal-body p').text('Please correct the following problems :'); + var ul = $('.modal-form-errors .modal-body ul'); + ul.empty(); + for (var i=0; i < a.length; i++) ul.append('<li>'+a[i]+'</li>'); + this.alert.modal('show'); + } + +} + +AccountValidator.prototype.showInvalidEmail = function() +{ + this.controlGroups[1].addClass('error'); + this.showErrors(['That email address is already in use.']); +} + +AccountValidator.prototype.showInvalidUserName = function() +{ + this.controlGroups[2].addClass('error'); + this.showErrors(['That username is already in use.']); +} + +AccountValidator.prototype.validateForm = function() +{ + var e = []; + for (var i=0; i < this.controlGroups.length; i++) this.controlGroups[i].removeClass('error'); + if (this.validateName(this.formFields[0].val()) == false) { + this.controlGroups[0].addClass('error'); e.push('Please Enter Your Name'); + } + if (this.validateEmail(this.formFields[1].val()) == false) { + this.controlGroups[1].addClass('error'); e.push('Please Enter A Valid Email'); + } + if (this.validateName(this.formFields[2].val()) == false) { + this.controlGroups[2].addClass('error'); + e.push('Please Choose A Username'); + } + if (this.validatePassword(this.formFields[3].val()) == false) { + this.controlGroups[3].addClass('error'); + e.push('Password Should Be At Least 6 Characters'); + } + if (e.length) this.showErrors(e); + return e.length === 0; +} + +
\ No newline at end of file diff --git a/public/js/form-validators/emailValidator.js b/public/js/form-validators/emailValidator.js new file mode 100644 index 0000000..5a87c04 --- /dev/null +++ b/public/js/form-validators/emailValidator.js @@ -0,0 +1,39 @@ + +function EmailValidator(){ + +// bind this to _local for anonymous functions // + + var _local = this; + +// modal window to allow users to request credentials by email // + _local.retrievePassword = $('#get-credentials'); + _local.retrievePassword.modal({ show : false, keyboard : true, backdrop : true }); + _local.retrievePasswordAlert = $('#get-credentials .alert'); + _local.retrievePassword.on('show', function(){ $('#get-credentials-form').resetForm(); _local.retrievePasswordAlert.hide();}); + +} + +EmailValidator.prototype.validateEmail = function(e) +{ + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(e); +} + +EmailValidator.prototype.showEmailAlert = function(m) +{ + this.retrievePasswordAlert.attr('class', 'alert alert-error'); + this.retrievePasswordAlert.html(m); + this.retrievePasswordAlert.show(); +} + +EmailValidator.prototype.hideEmailAlert = function() +{ + this.retrievePasswordAlert.hide(); +} + +EmailValidator.prototype.showEmailSuccess = function(m) +{ + this.retrievePasswordAlert.attr('class', 'alert alert-success'); + this.retrievePasswordAlert.html(m); + this.retrievePasswordAlert.fadeIn(500); +}
\ No newline at end of file diff --git a/public/js/form-validators/loginValidator.js b/public/js/form-validators/loginValidator.js new file mode 100644 index 0000000..066e822 --- /dev/null +++ b/public/js/form-validators/loginValidator.js @@ -0,0 +1,29 @@ + +function LoginValidator(){ + +// bind a simple alert window to this controller to display any errors // + + this.loginErrors = $('.modal-alert'); + this.loginErrors.modal({ show : false, keyboard : true, backdrop : true }); + + this.showLoginError = function(t, m) + { + $('.modal-alert .modal-header h3').text(t); + $('.modal-alert .modal-body p').text(m); + this.loginErrors.modal('show'); + } + +} + +LoginValidator.prototype.validateForm = function() +{ + if ($('#user-tf').val() == ''){ + this.showLoginError('Whoops!', 'Please enter a valid username'); + return false; + } else if ($('#pass-tf').val() == ''){ + this.showLoginError('Whoops!', 'Please enter a valid password'); + return false; + } else{ + return true; + } +}
\ No newline at end of file diff --git a/public/js/form-validators/resetValidator.js b/public/js/form-validators/resetValidator.js new file mode 100644 index 0000000..71c8792 --- /dev/null +++ b/public/js/form-validators/resetValidator.js @@ -0,0 +1,37 @@ + +function ResetValidator(){ + +// modal window to allow users to reset their password // + this.setPassword = $('#set-password'); + this.setPassword.modal({ show : false, keyboard : false, backdrop : 'static' }); + this.setPasswordAlert = $('#set-password .alert'); +} + +ResetValidator.prototype.validatePassword = function(s) +{ + if (s.length >= 6){ + return true; + } else{ + this.showAlert('Password Should Be At Least 6 Characters'); + return false; + } +} + +ResetValidator.prototype.showAlert = function(m) +{ + this.setPasswordAlert.attr('class', 'alert alert-error'); + this.setPasswordAlert.html(m); + this.setPasswordAlert.show(); +} + +ResetValidator.prototype.hideAlert = function() +{ + this.setPasswordAlert.hide(); +} + +ResetValidator.prototype.showSuccess = function(m) +{ + this.setPasswordAlert.attr('class', 'alert alert-success'); + this.setPasswordAlert.html(m); + this.setPasswordAlert.fadeIn(500); +}
\ No newline at end of file diff --git a/public/js/views/home.js b/public/js/views/home.js new file mode 100644 index 0000000..eda246a --- /dev/null +++ b/public/js/views/home.js @@ -0,0 +1,49 @@ + +$(document).ready(function(){ + + var hc = new HomeController(); + var av = new AccountValidator(); + + $('#account-form').ajaxForm({ + beforeSubmit : function(formData, jqForm, options){ + if (av.validateForm() == false){ + return false; + } else{ + // push the disabled username field onto the form data array // + formData.push({name:'user', value:$('#user-tf').val()}) + return true; + } + }, + success : function(responseText, status, xhr, $form){ + if (status == 'success') hc.onUpdateSuccess(); + }, + error : function(e){ + if (e.responseText == 'email-taken'){ + av.showInvalidEmail(); + } else if (e.responseText == 'username-taken'){ + av.showInvalidUserName(); + } + } + }); + $('#name-tf').focus(); + $('#github-banner').css('top', '41px'); + +// customize the account settings form // + + $('#account-form h1').text('Account Settings'); + $('#account-form #sub1').text('Here are the current settings for your account.'); + $('#user-tf').attr('disabled', 'disabled'); + $('#account-form-btn1').html('Delete'); + $('#account-form-btn1').addClass('btn-danger'); + $('#account-form-btn2').html('Update'); + +// setup the confirm window that displays when the user chooses to delete their account // + + $('.modal-confirm').modal({ show : false, keyboard : true, backdrop : true }); + $('.modal-confirm .modal-header h3').text('Delete Account'); + $('.modal-confirm .modal-body p').html('Are you sure you want to delete your account?'); + $('.modal-confirm .cancel').html('Cancel'); + $('.modal-confirm .submit').html('Delete'); + $('.modal-confirm .submit').addClass('btn-danger'); + +})
\ No newline at end of file diff --git a/public/js/views/login.js b/public/js/views/login.js new file mode 100644 index 0000000..27fe31d --- /dev/null +++ b/public/js/views/login.js @@ -0,0 +1,51 @@ + +$(document).ready(function(){ + + var lv = new LoginValidator(); + var lc = new LoginController(); + +// main login form // + + $('#login-form').ajaxForm({ + beforeSubmit : function(formData, jqForm, options){ + if (lv.validateForm() == false){ + return false; + } else{ + // append 'remember-me' option to formData to write local cookie // + formData.push({name:'remember-me', value:$("input:checkbox:checked").length == 1}) + return true; + } + }, + success : function(responseText, status, xhr, $form){ + if (status == 'success') window.location.href = '/home'; + }, + error : function(e){ + lv.showLoginError('Login Failure', 'Please check your username and/or password'); + } + }); + $('#user-tf').focus(); + +// login retrieval form via email // + + var ev = new EmailValidator(); + + $('#get-credentials-form').ajaxForm({ + url: '/lost-password', + beforeSubmit : function(formData, jqForm, options){ + if (ev.validateEmail($('#email-tf').val())){ + ev.hideEmailAlert(); + return true; + } else{ + ev.showEmailAlert("<b> Error!</b> Please enter a valid email address"); + return false; + } + }, + success : function(responseText, status, xhr, $form){ + ev.showEmailSuccess("Check your email on how to reset your password."); + }, + error : function(){ + ev.showEmailAlert("Sorry. There was a problem, please try again later."); + } + }); + +})
\ No newline at end of file diff --git a/public/js/views/reset.js b/public/js/views/reset.js new file mode 100644 index 0000000..c6a6166 --- /dev/null +++ b/public/js/views/reset.js @@ -0,0 +1,27 @@ + +$(document).ready(function(){ + + var rv = new ResetValidator(); + + $('#set-password-form').ajaxForm({ + beforeSubmit : function(formData, jqForm, options){; + rv.hideAlert(); + if (rv.validatePassword($('#pass-tf').val()) == false){ + return false; + } else{ + return true; + } + }, + success : function(responseText, status, xhr, $form){ + rv.showSuccess("Your password has been reset."); + setTimeout(function(){ window.location.href = '/'; }, 3000); + }, + error : function(){ + rv.showAlert("I'm sorry something went wrong, please try again."); + } + }); + + $('#set-password').modal('show'); + $('#set-password').on('shown', function(){ $('#pass-tf').focus(); }) + +});
\ No newline at end of file diff --git a/public/js/views/signup.js b/public/js/views/signup.js new file mode 100644 index 0000000..52de197 --- /dev/null +++ b/public/js/views/signup.js @@ -0,0 +1,39 @@ + +$(document).ready(function(){ + + var av = new AccountValidator(); + var sc = new SignupController(); + + $('#account-form').ajaxForm({ + beforeSubmit : function(formData, jqForm, options){ + return av.validateForm(); + }, + success : function(responseText, status, xhr, $form){ + if (status == 'success') $('.modal-alert').modal('show'); + }, + error : function(e){ + if (e.responseText == 'email-taken'){ + av.showInvalidEmail(); + } else if (e.responseText == 'username-taken'){ + av.showInvalidUserName(); + } + } + }); + $('#name-tf').focus(); + +// customize the account signup form // + + $('#account-form h1').text('Signup'); + $('#account-form #sub1').text('Please tell us a little about yourself'); + $('#account-form #sub2').text('Choose your username & password'); + $('#account-form-btn1').html('Cancel'); + $('#account-form-btn2').html('Submit'); + $('#account-form-btn2').addClass('btn-primary'); + +// setup the alert that displays when an account is successfully created // + + $('.modal-alert').modal({ show : false, keyboard : false, backdrop : 'static' }); + $('.modal-alert .modal-header h3').text('Success!'); + $('.modal-alert .modal-body p').html('Your account has been created.</br>Click OK to return to the login page.'); + +})
\ No newline at end of file diff --git a/views/login.ejs b/views/login.ejs index b938624..2997d9e 100644 --- a/views/login.ejs +++ b/views/login.ejs @@ -1,19 +1,60 @@ <% include header %> + <link rel="stylesheet" href="/css/login.css" /> </head> <body> +<div id="login-container"> + <form method="post" id="login-form" class="well span4"> + <h1>Hello!</h1> + <p class="subheading">Please Login To Your Account</p> + <label>Username </label> + <input type="text" name="user" id="user-tf" class="span4 required"> + <label>Password</label> + <input type="password" name="pass" id="pass-tf" class="span4 required"> + <button type="submit" id="btn-login" class="btn btn-primary"><i class="icon-lock icon-white"></i>Sign in</button> + <label id="remember-me" class="checkbox">Remember Me + <input type="checkbox" checked="checked"> + </label> + <div class="clear-fix"></div> + <hr> + <div class="btm-links"><a href="#" id="forgot-password">Forgot Your Password? </a><a href="/signup" id="create-account">Create An Account</a></div> + </form> +</div> +<div class="modal-alert modal hide fade"> + <div class="modal-header"> + <button data-dismiss="modal" class="close">x</button> + <h3></h3> + </div> + <div class="modal-body"> + <p></p> + </div> + <div class="modal-footer"> + <button data-dismiss="modal" id="ok" class="btn btn-warning">OK</button> + </div> +</div> +<div id="get-credentials" class="modal-single-input modal hide fade"> + <div class="modal-header"> + <button data-dismiss="modal" class="close">x</button> + <h3>Retrieve Password</h3> + </div> + <div class="modal-body"> + <form method="post" id="get-credentials-form" class="well span5"> + <p>Please enter the email address associated with your account</p> + <input type="text" name="email" id="email-tf" class="span5 required"> + <button type="submit" id="submit" class="btn btn-primary">Submit</button> + <button data-dismiss="modal" id="cancel" class="btn">Cancel</button> + <div class="alert alert-error hide"></div> + <button data-dismiss="alert" class="close"></button> + </form> + </div> + <div class="modal-footer"></div> +</div> - <div class="container"> - <form class="form-signin"> - <h2 class="form-signin-heading">Please sign in</h2> - <input type="text" class="input-block-level" placeholder="Email address"> - <input type="password" class="input-block-level" placeholder="Password"> - <label class="checkbox"> - <input type="checkbox" value="remember-me"> Remember me - </label> - <button class="btn btn-primary" type="submit">Sign in</button> - </form> - </div> <!-- /container --> +<script src="/js/views/login.js"></script> +<script src="/js/jquery.form.js"></script> +<script src="/js/controllers/loginController.js"></script> +<script src="/js/form-validators/loginValidator.js"></script> +<script src="/js/form-validators/emailValidator.js"></script> <% include footer %> |