From 2678de902d8f6dfb67cff7f80e6524ac78ef85b8 Mon Sep 17 00:00:00 2001 From: Matthew Harrison-Jones Date: Thu, 12 Sep 2013 09:59:58 +0100 Subject: [PATCH] Improved Auth screen markup and validation checks * Signup now focuses on 'name' on load * Fixed fade in on auth forms to work with `display: table` * The 'name' field is required on Sign up forms * The length check on the Signup form is in order of inputs * Added check for password length * Changed the auth form class names to better represent individual pages * Updated CasperJS tests --- .../sass/layouts/{login.scss => auth.scss} | 7 +- core/client/assets/sass/screen.scss | 2 +- core/client/router.js | 4 +- core/client/views/login.js | 85 +++++++++++++------ core/server/controllers/admin.js | 6 +- core/server/views/forgotten.hbs | 4 + core/server/views/signup.hbs | 2 +- core/test/functional/admin/01_login_test.js | 42 ++++----- core/test/functional/base.js | 13 +++ 9 files changed, 102 insertions(+), 63 deletions(-) rename core/client/assets/sass/layouts/{login.scss => auth.scss} (98%) create mode 100644 core/server/views/forgotten.hbs diff --git a/core/client/assets/sass/layouts/login.scss b/core/client/assets/sass/layouts/auth.scss similarity index 98% rename from core/client/assets/sass/layouts/login.scss rename to core/client/assets/sass/layouts/auth.scss index c19fd491be..c8b67569dc 100644 --- a/core/client/assets/sass/layouts/login.scss +++ b/core/client/assets/sass/layouts/auth.scss @@ -1,5 +1,5 @@ /* - * These styles control elements specific to the Ghost admin login screen. + * These styles control elements specific to the Ghost admin login / signup screens. * * Table of Contents: * @@ -14,6 +14,7 @@ ============================================================================= */ .ghost-login, +.ghost-signup, .ghost-forgotten { color: $midgrey; background: $darkgrey; @@ -28,7 +29,9 @@ }//.ghost-login -.login-box { +.login-box, +.signup-box, +.forgotten-box { max-width: 530px; height: 90%; margin: 0 auto; diff --git a/core/client/assets/sass/screen.scss b/core/client/assets/sass/screen.scss index 944eb753ef..9cd8b36ecc 100644 --- a/core/client/assets/sass/screen.scss +++ b/core/client/assets/sass/screen.scss @@ -40,7 +40,7 @@ @import "layouts/editor"; /* The write/edit post screen. */ - @import "layouts/login"; + @import "layouts/auth"; /* The login screen. */ @import "layouts/errors"; diff --git a/core/client/router.js b/core/client/router.js index b3152f7ac9..4ad8dd881f 100644 --- a/core/client/router.js +++ b/core/client/router.js @@ -19,7 +19,7 @@ }, signup: function () { - Ghost.currentView = new Ghost.Views.Signup({ el: '.js-login-box' }); + Ghost.currentView = new Ghost.Views.Signup({ el: '.js-signup-box' }); }, login: function () { @@ -27,7 +27,7 @@ }, forgotten: function () { - Ghost.currentView = new Ghost.Views.Forgotten({ el: '.js-login-box' }); + Ghost.currentView = new Ghost.Views.Forgotten({ el: '.js-forgotten-box' }); }, blog: function () { diff --git a/core/client/views/login.js b/core/client/views/login.js index 0ef5ceb0d4..78b8388edc 100644 --- a/core/client/views/login.js +++ b/core/client/views/login.js @@ -2,17 +2,14 @@ (function () { "use strict"; + Ghost.Views.Login = Ghost.View.extend({ - Ghost.SimpleFormView = Ghost.View.extend({ initialize: function () { this.render(); - $(".js-login-box").fadeIn(500, function () { + $(".js-login-box").css({"opacity": 0}).animate({"opacity": 1}, 500, function () { $("[name='email']").focus(); }); - } - }); - - Ghost.Views.Login = Ghost.SimpleFormView.extend({ + }, templateName: "login", @@ -48,7 +45,14 @@ } }); - Ghost.Views.Signup = Ghost.SimpleFormView.extend({ + Ghost.Views.Signup = Ghost.View.extend({ + + initialize: function () { + this.render(); + $(".js-signup-box").css({"opacity": 0}).animate({"opacity": 1}, 500, function () { + $("[name='name']").focus(); + }); + }, templateName: "signup", @@ -62,29 +66,56 @@ email = this.$el.find('.email').val(), password = this.$el.find('.password').val(); - $.ajax({ - url: '/ghost/signup/', - type: 'POST', - data: { - name: name, - email: email, - password: password - }, - success: function (msg) { - window.location.href = msg.redirect; - }, - error: function (xhr) { - Ghost.notifications.addItem({ - type: 'error', - message: Ghost.Views.Utils.getRequestErrorMessage(xhr), - status: 'passive' - }); - } - }); + if (!name) { + Ghost.notifications.addItem({ + type: 'error', + message: "Please enter a name", + status: 'passive' + }); + } else if (!email) { + Ghost.notifications.addItem({ + type: 'error', + message: "Please enter an email", + status: 'passive' + }); + } else if (!password) { + Ghost.notifications.addItem({ + type: 'error', + message: "Please enter a password", + status: 'passive' + }); + } else { + $.ajax({ + url: '/ghost/signup/', + type: 'POST', + data: { + name: name, + email: email, + password: password + }, + success: function (msg) { + window.location.href = msg.redirect; + }, + error: function (xhr) { + Ghost.notifications.addItem({ + type: 'error', + message: Ghost.Views.Utils.getRequestErrorMessage(xhr), + status: 'passive' + }); + } + }); + } } }); - Ghost.Views.Forgotten = Ghost.SimpleFormView.extend({ + Ghost.Views.Forgotten = Ghost.View.extend({ + + initialize: function () { + this.render(); + $(".js-forgotten-box").css({"opacity": 0}).animate({"opacity": 1}, 500, function () { + $("[name='email']").focus(); + }); + }, templateName: "forgotten", diff --git a/core/server/controllers/admin.js b/core/server/controllers/admin.js index e5bf35ecc0..75ba784eff 100644 --- a/core/server/controllers/admin.js +++ b/core/server/controllers/admin.js @@ -116,7 +116,7 @@ adminControllers = { } }, 'login': function (req, res) { - res.render('signup', { + res.render('login', { bodyClass: 'ghost-login', hideNavbar: true, adminNav: setSelected(adminNavbar, 'login') @@ -161,7 +161,7 @@ adminControllers = { }, 'signup': function (req, res) { res.render('signup', { - bodyClass: 'ghost-login', + bodyClass: 'ghost-signup', hideNavbar: true, adminNav: setSelected(adminNavbar, 'login') }); @@ -189,7 +189,7 @@ adminControllers = { }, 'forgotten': function (req, res) { - res.render('signup', { + res.render('forgotten', { bodyClass: 'ghost-forgotten', hideNavbar: true, adminNav: setSelected(adminNavbar, 'login') diff --git a/core/server/views/forgotten.hbs b/core/server/views/forgotten.hbs new file mode 100644 index 0000000000..94a72e3aba --- /dev/null +++ b/core/server/views/forgotten.hbs @@ -0,0 +1,4 @@ +{{!< default}} +
+ +
\ No newline at end of file diff --git a/core/server/views/signup.hbs b/core/server/views/signup.hbs index 8b28bdc67a..39857171b6 100644 --- a/core/server/views/signup.hbs +++ b/core/server/views/signup.hbs @@ -1,4 +1,4 @@ {{!< default}} -
+ diff --git a/core/test/functional/admin/01_login_test.js b/core/test/functional/admin/01_login_test.js index fd62adcbb5..23378b14a1 100644 --- a/core/test/functional/admin/01_login_test.js +++ b/core/test/functional/admin/01_login_test.js @@ -17,15 +17,13 @@ casper.test.begin('Ensure a User is Registered', 2, function suite(test) { casper.start(url + 'ghost/signup/').viewport(1280, 1024); - casper.waitFor(function checkOpaque() { - return this.evaluate(function () { - var loginBox = document.querySelector('.login-box'); - return window.getComputedStyle(loginBox).getPropertyValue('display') === "table" - && window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1"; + casper.waitForOpaque(".signup-box", + function then() { + this.fill("#signup", newUser, true); + }, + function onTimeout() { + test.fail('Sign up form didn\'t fade in.'); }); - }, function then() { - this.fill("#signup", user, true); - }); casper.waitForSelectorTextChange('.notification-error', function onSuccess() { test.assertSelectorHasText('.notification-error', 'already registered'); @@ -86,18 +84,13 @@ casper.test.begin("Can't spam it", 4, function suite(test) { test.assertTitle("", "Ghost admin has no title"); }).viewport(1280, 1024); - casper.waitFor(function checkOpaque() { - return this.evaluate(function () { - var loginBox = document.querySelector('.login-box'); - - return window.getComputedStyle(loginBox).getPropertyValue('display') === "table" - && window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1"; + casper.waitForOpaque(".login-box", + function then() { + this.fill("#login", falseUser, true); + }, + function onTimeout() { + test.fail('Sign in form didn\'t fade in.'); }); - }, function then() { - this.fill("#login", falseUser, true); - }, function onTimeout() { - test.fail('Sign in form didn\'t fade in.'); - }); casper.wait(200, function doneWait() { this.fill("#login", falseUser, true); @@ -127,15 +120,10 @@ casper.test.begin("Can login to Ghost", 4, function suite(test) { test.assertTitle("", "Ghost admin has no title"); }).viewport(1280, 1024); - casper.waitFor(function checkOpaque() { - return casper.evaluate(function () { - var loginBox = document.querySelector('.login-box'); - return window.getComputedStyle(loginBox).getPropertyValue('display') === "table" - && window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1"; + casper.waitForOpaque(".login-box", + function then() { + this.fill("#login", user, true); }); - }, function then() { - this.fill("#login", user, true); - }); casper.waitForResource(/ghost\/$/, function testForDashboard() { test.assertUrlMatch(/ghost\/$/, 'We got redirected to the Ghost page'); diff --git a/core/test/functional/base.js b/core/test/functional/base.js index ab3f3e2c66..e7a0dec100 100644 --- a/core/test/functional/base.js +++ b/core/test/functional/base.js @@ -27,6 +27,11 @@ var host = casper.cli.options.host || 'localhost', email = casper.cli.options.email || 'ghost@tryghost.org', password = casper.cli.options.password || 'Sl1m3rson', url = "http://" + host + (noPort ? '/' : ":" + port + "/"), + newUser = { + name: "Test User", + email: email, + password: password + }, user = { email: email, password: password @@ -51,6 +56,14 @@ casper.writeContentToCodeMirror = function (content) { return this; }; +casper.waitForOpaque = function (classname, then, timeout) { + casper.waitFor(function checkOpaque() { + return this.evaluate(function (element) { + var target = document.querySelector(element); + return window.getComputedStyle(target).getPropertyValue('opacity') === "1"; + }, classname); + }, then, timeout); +}; // ## Debugging // output all errors to the console