From 8a3ece46ef6bfeefaa27f53f199c285d0062f841 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Wed, 19 Oct 2011 19:23:55 -0600 Subject: [PATCH] better client-side form validation; layout tweaks --- Makefile.PL | 1 + lib/Chatty/Controller/Root.pm | 83 +++++++++++++++--- lib/Chatty/Form/Login.pm | 2 +- lib/Chatty/Form/Register.pm | 18 ++-- root/static/css/common.css | 8 +- root/static/css/validationEngine.jquery.css | 2 +- root/static/img/chat.png | Bin 0 -> 4774 bytes root/static/js/jquery.validationEngine-en.js | 86 ++++++++++--------- root/tt/index.tt | 11 --- root/tt/login.tt | 12 ++- root/tt/register.tt | 32 +------ root/tt/wrapper.tt | 11 +-- 12 files changed, 155 insertions(+), 111 deletions(-) create mode 100644 root/static/img/chat.png delete mode 100644 root/tt/index.tt diff --git a/Makefile.PL b/Makefile.PL index c5c28ca..baf385c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -19,6 +19,7 @@ requires 'Catalyst::Plugin::Session::Store::FastMmap'; requires 'Catalyst::Plugin::Session::State::Cookie'; requires 'Catalyst::Plugin::Unicode::Encoding'; requires 'Catalyst::Action::RenderView'; +requires 'JSON'; requires 'Moose'; requires 'namespace::autoclean'; requires 'Config::General'; # This should reflect the config file format you've chosen diff --git a/lib/Chatty/Controller/Root.pm b/lib/Chatty/Controller/Root.pm index ab0bfcd..f526d41 100644 --- a/lib/Chatty/Controller/Root.pm +++ b/lib/Chatty/Controller/Root.pm @@ -10,6 +10,8 @@ BEGIN { extends 'Catalyst::Controller' } # __PACKAGE__->config(namespace => ''); +use JSON 'encode_json'; + use Chatty::Form::Login; use Chatty::Form::Register; @@ -44,7 +46,9 @@ The root page (/) =cut sub index :Path :Args(0) { - my ( $self, $c ) = @_; + my ($self, $c) = @_; + $c->go('/chat/list') if ($c->user_exists); + $c->go('login'); } =head2 login @@ -68,13 +72,12 @@ sub login :Local :Args(0) { $c->change_session_id; my $user = $c->user->get('username'); $c->flash->{message} .= "Hi, $user! You are now logged in."; - $c->response->redirect($c->uri_for('/')); + $c->res->redirect($c->uri_for_action('index')); + return; } - else { - $c->flash->{error} = "Log-in failed! Try again, I guess."; - $c->response->redirect($c->uri_for('login')); - } - } + }; + $c->flash->{error} = "Log-in failed! Try again, I guess."; + $c->res->redirect($c->uri_for_action('login')); } =head2 logout @@ -89,7 +92,7 @@ sub logout :Local :Args(0) { $c->logout; $c->flash->{message} = "Goodbye! You have been logged out."; } - $c->response->redirect($c->uri_for('/')); + $c->res->redirect($c->uri_for_action('index')); } =head2 register @@ -109,12 +112,71 @@ sub register :Local :Args(0) { params => $c->req->params ); - return unless $self->register_form->is_valid; + if (!$self->register_form->is_valid) { + if ($c->req->method eq 'POST') { + $c->stash->{error} = "The form has a validation error. Try again..."; + } + return; + } $c->flash->{message} = "Registration complete. "; $c->forward('login'); } +=head2 register_validate + +Check whether or not a username is available. + +=cut + +sub register_validate :Local :Args(0) { + my ($self, $c) = @_; + + my $id = $c->req->param('fieldId'); + my $username = $c->req->param('fieldValue'); + + my $json_arr = []; + + if ($username) { + my $account = $c->model('DB::Account')->find({username => $username}); + if (!$account) { + $json_arr = ["$id", 1, "This username is available. Nice!"]; + } + else { + $json_arr = ["$id", 0, "This username is taken."]; + } + } + else { + $json_arr = ["$id", 0, "Invalid arguments to check script."]; + } + $c->res->content_type("application/json"); + $c->res->body(encode_json($json_arr)); +} + +=head2 access_denied + +Standard 403 error page + +=cut + +sub access_denied :Private { + my ($self, $c) = @_; + $c->res->body('Access denied.'); + $c->res->status(403); +} + +=head2 missing + +Standard 404 error page + +=cut + +sub missing :Private { + my ($self, $c) = @_; + $c->res->body('Page not found.'); + $c->res->status(404); +} + =head2 default Standard 404 error page @@ -123,8 +185,7 @@ Standard 404 error page sub default :Path { my ($self, $c) = @_; - $c->response->body('Page not found.'); - $c->response->status(404); + $c->detach('missing'); } =head2 end diff --git a/lib/Chatty/Form/Login.pm b/lib/Chatty/Form/Login.pm index aa25b1d..6e88169 100644 --- a/lib/Chatty/Form/Login.pm +++ b/lib/Chatty/Form/Login.pm @@ -2,11 +2,11 @@ package Chatty::Form::Login; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; +use namespace::autoclean; has_field 'username' => (label => 'Username', required => 1); has_field 'password' => (type => 'Password', required => 1); has_field 'submit' => (type => 'Submit', value => 'Login'); -no HTML::FormHandler::Moose; __PACKAGE__->meta->make_immutable; 1; diff --git a/lib/Chatty/Form/Register.pm b/lib/Chatty/Form/Register.pm index 9ae939e..bf0ec64 100644 --- a/lib/Chatty/Form/Register.pm +++ b/lib/Chatty/Form/Register.pm @@ -2,19 +2,19 @@ package Chatty::Form::Register; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Model::DBIC'; +use namespace::autoclean; has '+item_class' => (default => 'Account'); - -has_field 'username' => (label => 'User Nickname', required => 1, unique => 1); -has_field 'password' => (type => 'Password', required => 1); -has_field 'password_confirm' => (type => 'PasswordConf', required => 1); -has_field 'email' => (type => 'Email', label => 'Email address'); -has_field 'submit' => (type => 'Submit', value => 'Register'); - has '+unique_messages' => (default => sub { {username => 'Username is already registered'}; - }); +}); + +has_field 'username' => (input_class => 'validate[required,ajax[register_validate]]', label => 'Username', required => 1, unique => 1); +has_field 'password' => (input_class => 'validate[required]', type => 'Password', required => 1); +has_field 'password_confirm' => (input_class => 'validate[required,equals[password]]', type => 'PasswordConf', required => 1); +has_field 'email' => (input_class => 'validate[custom[email]]', type => 'Email', label => 'Email address'); +has_field 'submit' => (type => 'Submit', value => 'Register'); +has_field 'reset' => (type => 'Reset', value => 'Reset'); -no HTML::FormHandler::Moose; __PACKAGE__->meta->make_immutable; 1; diff --git a/root/static/css/common.css b/root/static/css/common.css index 023d30e..6474f5b 100644 --- a/root/static/css/common.css +++ b/root/static/css/common.css @@ -50,6 +50,7 @@ label { margin: 5px; padding: 10px; border: 2px solid black; + border-radius: 5px; background: white; } @@ -62,7 +63,7 @@ label { } #footer { - padding: 0; + padding: 10px 0 0 0; height: 31px; line-height: 31px; font-size: 0.8em; @@ -95,3 +96,8 @@ label { background: #c66; } +form div { + height: 32px; + line-height: 32px; +} + diff --git a/root/static/css/validationEngine.jquery.css b/root/static/css/validationEngine.jquery.css index 5500bee..b733ad3 100755 --- a/root/static/css/validationEngine.jquery.css +++ b/root/static/css/validationEngine.jquery.css @@ -25,7 +25,7 @@ position:relative; z-index:5001; color: #fff; - width: 150px; + width: 175px; font-family: tahoma; font-size: 11px; border: 2px solid #ddd; diff --git a/root/static/img/chat.png b/root/static/img/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..3e1af263b570e7d9e4677ee3d6996afb38ee3139 GIT binary patch literal 4774 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 - Toy chat app written in Perl/Catalyst -

-This app lets you chat with other registered chatters. Cool! Once you are -registered and logged-in, you will be allowed to join a chat room and get -chatty. -

-[% IF ! c.user_exists -%] -[% INCLUDE login.tt -%] -[% ELSE %] -Log Out -[% END -%] diff --git a/root/tt/login.tt b/root/tt/login.tt index 3720e26..74eefa5 100644 --- a/root/tt/login.tt +++ b/root/tt/login.tt @@ -1,5 +1,10 @@ [% META title = 'Log In' -%] -

Log In

+

+This app lets you chat with other registered chatters. Cool! Once you are +registered and logged-in, you will be allowed to join a chat room and get +chatty. +

+

Log In

[% IF ! c.user_exists -%] [% form.render %] -

Register

+

Register

-If you don't already have an account, go register! +If you don't already have an account, you should +go register now!

[% ELSE -%]

You are already logged in.

diff --git a/root/tt/register.tt b/root/tt/register.tt index c73e161..250654b 100644 --- a/root/tt/register.tt +++ b/root/tt/register.tt @@ -1,36 +1,12 @@ [% META title = 'Register' -%] [% BLOCK js -%] -$('#form').validationEngine(); -$('#form button[type=reset]').click(function() { - $('#form').validationEngine('hideAll'); +$('form').validationEngine(); +$('form input[type=reset]').click(function() { + $('form').validationEngine('hideAll'); }); [% END -%] -

Register

+

Register

[% IF ! c.user_exists -%] - [% form.render %] [% ELSE -%]

You are already registered and logged in. There is no need to register again.

diff --git a/root/tt/wrapper.tt b/root/tt/wrapper.tt index 6fad196..f4d497f 100644 --- a/root/tt/wrapper.tt +++ b/root/tt/wrapper.tt @@ -21,8 +21,13 @@ [% END -%]
+
+[% IF c.user_exists -%] + Log Out +[% END -%] +
+ Chat! [% content -%] -