[Catalyst-commits] r13843 - trunk/examples/CatalystAdvent/root/2010/pen

dhoss at dev.catalyst.perl.org dhoss at dev.catalyst.perl.org
Tue Dec 14 20:26:37 GMT 2010


Author: dhoss
Date: 2010-12-14 20:26:37 +0000 (Tue, 14 Dec 2010)
New Revision: 13843

Added:
   trunk/examples/CatalystAdvent/root/2010/pen/001_getting-started.pod
Removed:
   trunk/examples/CatalystAdvent/root/2010/pen/TODO
Log:
added Sir et al's article draft

Added: trunk/examples/CatalystAdvent/root/2010/pen/001_getting-started.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2010/pen/001_getting-started.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2010/pen/001_getting-started.pod	2010-12-14 20:26:37 UTC (rev 13843)
@@ -0,0 +1,634 @@
+=head1 Getting Started with Catalyst and jQuery (and jQuery UI)
+
+=head2 A few initial comments
+
+For the duration of this article we'll be assuming that you want to use jQuery
+and jQuery-UI with Catalyst, and that you'll be using the Template Toolkit for
+your templating engine.  Of course, this is perl and There's More Than One Way
+To Do It -- so you can use something else instead of TT, or tweak our 
+suggestions a bit.  If you do, things will probably Just Work.   Have fun, and
+stay DRY.
+
+This article is aimed at developers new to Catalyst and especially Catalyst
+with jQuery.  It is designed to help someone go from 0 to App as quickly as
+possible.
+
+The commands in the article assume you're using Linux.  If you aren't, adjust
+the commands accordingly (or switch to Linux ;).
+
+=head2 Background knowledge
+
+This article assumes you already know some things.  If you don't,
+please follow the provided links to read about a few key topics before continuing
+with this article.  You can probably make it through without knowing some
+of them, but if you're reading this, all of them will make your life easier.
+
+=over
+
+=item Catalyst (L<http://www.catalystframework.org/>)
+
+The perl MVC framework
+
+=item HTML::FormHandler (L<http://search.cpan.org/~gshank/HTML-FormHandler-0.32005/lib/HTML/FormHandler.pm>)
+
+For creating, displaying, and validating forms
+
+=item jQuery (L<http://jquery.com/>)
+
+The Write Less, Do More, JavaScript Library
+
+=item jQuery UI (L<http://jqueryui.com/>)
+
+UI enhancement framework on top of jQuery
+
+=item Template Toolkit (L<http://template-toolkit.org/>)
+
+A fast, flexible and highly extensible template processing system.
+
+=back
+
+=head2 Setting up the project
+
+For our purposes, we'll be working on a project that depicts a pizzaria
+(called, creatively, "Pizzaria") that takes orders online.  
+
+=head3 Choosing a namespace
+
+Because our company is called Pizzaria, we're going to call our app the same.
+Now, we could simply run
+
+	catalyst.pl Pizzaria
+
+and get an application that's set up like this:
+
+	./Pizzaria
+	./Pizzaria/script
+	./Pizzaria/script/...
+	./Pizzaria/lib
+	./Pizzaria/lib/Pizzaria
+	./Pizzaria/lib/Pizzaria/Model
+	./Pizzaria/lib/Pizzaria/View
+	./Pizzaria/lib/Pizzaria/Controller
+	./Pizzaria/lib/Pizzaria/Controller/Root.pm
+	./Pizzaria/lib/Pizzaria.pm
+	./Pizzaria/root
+	./Pizzaria/root/static
+	./Pizzaria/root/static/images
+	./Pizzaria/root/static/images/...
+	./Pizzaria/root/favicon.ico
+	./Pizzaria/t
+	./Pizzaria/t/...
+
+That's fine, but it has one limitation that's sort of needless:  it assumes
+that the web interface is the only one we'll be making.  As a matter of good
+practice, let's just start off right and name it according to what we're
+actually making:  A B<web> interface to our Pizzaria's software.
+
+	$ catalyst.pl Pizzaria::Web
+	created "Pizzaria-Web"
+	created "Pizzaria-Web/script"
+	created "Pizzaria-Web/lib"
+	created "Pizzaria-Web/root"
+	created "Pizzaria-Web/root/static"
+	created "Pizzaria-Web/root/static/images"
+	created "Pizzaria-Web/t"
+	created "Pizzaria-Web/lib/Pizzaria/Web"
+	created "Pizzaria-Web/lib/Pizzaria/Web/Model"
+	created "Pizzaria-Web/lib/Pizzaria/Web/View"
+	created "Pizzaria-Web/lib/Pizzaria/Web/Controller"
+	created "Pizzaria-Web/pizzaria_web.conf"
+	created "Pizzaria-Web/lib/Pizzaria/Web.pm"
+	created "Pizzaria-Web/lib/Pizzaria/Web/Controller/Root.pm"
+	created "Pizzaria-Web/README"
+	...
+
+That's better.  Now when we are ready to create other interfaces to our
+application, it won't require any refactoring; we'll simply be able to add
+Pizzaria::CLI, etc.
+
+Because I like to, I always rename the app's directory to omit the "-Web":
+
+	$ mv Pizzaria-Web Pizzaria
+	$ cd Pizzaria
+
+=head3 Setting up jQuery and jQuery UI
+
+For ease, throughout the remainder of this article, I'll refer to jQuery and
+jQuery UI as "jQuery".  You may, of course, use jQuery without the UI libs,
+and you may use the UI without ever manually utilizing jQuery (though it will
+still be loaded as a dependency, of course), but for our purposes, I'll assume
+that you're going to be using both.
+
+Because jQuery is a client-side JavaScript library, most of the actual use of
+it will be done through the templates.  There's a lot we can do in Catalyst
+to make things easier in jQuery, but we'll have to get to those later.  Let's
+get started.
+
+=head4 The jQuery Frameworks
+
+First, in setting up our repo, we'll create a place for jQuery to live.
+Remember that whatever we put under the ./root/static directory will be
+files that we're expecting to access directly with hyperlinks; that means
+we can effectively consider this something like the "public API" of our 
+application resources.  With that in mind, you want the names to be
+semantically meaningful.  And, as always, Do The Right Thing -- don't 
+take shortcuts =)
+
+We'll have all our javascript live in C<./root/static/javascript/>.  
+Similarly, css will live in C<./root/static/css/>, images in
+C<./root/static/images/>, and so forth.  Our templates will live in 
+C<./root/src/>.
+
+	$	mkdir -p ./root/static/javascript/ext
+
+We'll put all third-party javascript libs in C<./root/static/javascript/ext/>
+and know never to edit anything in there (right? =)  Separating external libs
+that way will also help future maintainers and developers to understand how
+the application is structured.
+
+Next, we'll download the latest, greatest versions of jQuery and jQuery UI
+from their respective web pages (linked above) and unzip them into those 
+directories.  When you're done, your directory structure should look like
+this:
+
+	./root/static/javascript/ext/jquery
+	./root/static/javascript/ext/jquery/jquery-1.4.2.min.js
+	./root/static/javascript/ext/jquery-ui
+	./root/static/javascript/ext/jquery-ui/AUTHORS.txt
+	./root/static/javascript/ext/jquery-ui/jquery-1.4.2.js
+	./root/static/javascript/ext/jquery-ui/ui
+	./root/static/javascript/ext/jquery-ui/docs
+	...
+
+=head4 Plugins (third-party and in-house)
+
+One of the great things about jQuery is the very active user community.  You
+should get into the habit of using jQuery plugins liberally; if you choose
+them well, they're light-weight, efficient, and very effective.  Let's create
+a place for our jQuery plugins to live.
+
+	$ mkdir -p ./root/static/javascript/ext/plugins/jquery
+	$ mkdir -p ./root/static/javascript/ext/plugins/jquery-ui
+
+Of course, if we start using other third-party JavaSCript plugins we can
+just add them.  For example, if we wanted to use CKEditor, as I did for a 
+project at work recently, or Flot, or any other third-party JS lib, 
+it would be very easy simply to add the spaces for it.
+
+	$ # mkdir -p ./root/static/javascript/ext/ckeditor
+	$ # mkdir -p ./root/static/javascript/ext/plugins/ckeditor
+
+and we can just add files into those spaces as we need to.  (I commented out
+the commands below in case someone isn't reading carefully
+and blindly copies/pastes all the commands in this article =)
+
+We're also going to want to be developing internal plugins from time to
+time, probably.  Let's create a place for those to live as well, for the sake
+of completeness.
+
+	$ mkdir -p ./root/static/javascript/plugins/jquery
+
+Now when you want to create a generic jQuery plugin (that's not specific to
+a particular part of your application's view domain) just drop it into that
+directory.
+
+Great -- now we're ready to get started with our app development.
+
+=head2 Data is everything
+
+Your data is everything.  You can always fix a bad flow of logic in your
+controller, or even fix a bunk interface to your models... but if you have
+bad data, you're stuck.  For that reason, you should be thinking of your
+application as a data management process.  Everything in your application
+is about how you create, retreive, update, or delete data (CRUD).
+
+=head3 The Schema
+
+For our purposes, let's assume that you're using MySQL (L<http://www.mysql.com/>)
+with L<DBIx::Class> and creating your schema with L<DBIx::Class::Schema::Loader>.
+Further, we'll just assume you've already created your schema using the
+following SQL:
+
+	CREATE TABLE IF NOT EXISTS `user` (
+		id INT(64) NOT NULL AUTO_INCREMENT,
+		password VARCHAR(32) NOT NULL default '',
+		email VARCHAR(32) NOT NULL default '',
+		first_name VARCHAR(32) NOT NUL default '',,
+		last_name VARCHAR(32) NOT NUL default '',,
+		registered TIMESTAMP NOT NULL DEFFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+		PRIMARY KEY (`id`),
+		UNIQUE (`email`)
+	) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+	CREATE TABLE IF NOT EXISTS `order` (
+		id INT(64) NOT NULL AUTO_INCREMENT,
+		user INT(64) NOT NULL DEFAULT '',
+		total INT(64) NOT NULL DEFAULT 0,
+		created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+		FOREIGN KEY (`user`) REFERENCES `user` (`id`)
+	) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+	-- ... and so on with tables for specials, toppings, or whatever.
+
+=head2 Inputs matter
+
+If the way you store data is critical, then just as critical is the way you
+B<acquire> it.  In a web app, much of the time, that's going to be done
+through the venerable HTML form.
+
+=head3 Defining Forms
+
+Forms are critical.  They control what information we take in, and when we
+validate our data, we validate what's come through our forms.  In fact, 
+forms are so critical we don't want them to be treated as second-class
+elements of our application; they are key components that deserve focused
+attention and first-class status.
+
+Now, for the most part forms we use in one interface are unlikely to be used
+others (when was the last time you filled out a form in a CLI?).  For that 
+reason, we're going to create a namespace in which to keep our forms; a
+dedicated library wing just for web forms.  All forms will go into this
+namespace, and no forms will be created without them.  Remember:  forms are 
+first-class members of our application; they are the user's interface to 
+our database, and our interface to the users.
+
+We'll keep our forms in Pizzaria::Web::Form.  For example, if we want a form
+to create/register a new user, it might be in Pizzaria::Web::Form::User::Register, or
+if we want to update a user's profile, we could create a new form in
+Pizzaria::Web::Form::User::Update.
+
+	$ mkdir -p ./lib/Pizzaria/Web/Form
+
+With a little forethought, we can definitely save ourselves a lot of
+repetition.  We already said that the two main functions we want users to
+be able to do is register as users and modify their profiles.  It seems
+very likely that both forms will have a lot of fields in common, and 
+that we'll want the same restraints on fields shared by both forms.  So
+how do we usually do that?  Subclassing.  We're going to use the same
+concept here.  Let's create a form object for C<Pizzaria::Web::Form::User>,
+C<Pizzaria::Web::Form::User::Register>, and C<Pizzaria::Web::Form::User::Update>,
+in which our core functionality is described in the first, and the latter
+two contain only overriding modifications to the base class.
+
+Let's create a form for creating new users.
+
+	$ mkdir -p ./lib/Pizzaria/Web/Form/User
+	$ touch ./lib/Pizzaria/Web/Form/User.pm
+	$ touch ./lib/Pizzaria/Web/Form/User/Register.pm
+	$ touch ./lib/Pizzaria/Web/Form/User/Update.pm
+
+Great.  Next, let's create our base class in C<Pizzaria::Web::Form::User>.  
+Before you go any further, read this excellent introduction to 
+HTML::FormHandler (L<http://www.catalyzed.org/2010/03/an-introduction-to-formhandler.html>)
+if you haven't already.  We're lifting code from there I<en masse> and life
+will be easier for you if you understand what's covered there =)
+
+...
+
+Our ::User package now looks like this:
+
+	package Pizzaria::Web::Form::User;
+
+	use HTML::FormHandler::Moose;
+	extends 'HTML::FormHandler::Model::DBIC';
+	with 'HTML::FormHandler::Render::Table';
+
+	has '+item_class' => (default => 'User');
+
+	has_field 'first_name' => (type => 'Text');
+	has_field 'last_name'  => (type => 'Text');
+	has_field 'email'      => (	
+		type => 'Email',
+		required => 1,
+		unique => 1,
+	);
+	has_field 'password'         => (type => 'Password');
+	has_field 'password_confirm' => (type => 'PasswordConf');
+
+	has '+unique_messages' =>	(
+		default => sub { 
+			{email => 'Email already registered'}
+		}
+	);
+
+	no HTML::FormHandler::Moose;
+	__PACKAGE__->meta->make_immutable;
+	1;
+
+Notice that we've omitted the "submit" field.  That's because this base class
+is never going to be used directly; it's just a foundation for our other user
+form classes.  Now we create our registration form:
+
+	package Pizzaria::Web::Form::User::Register;
+	
+	use HTML::FormHandler::Moose;
+	extends 'Pizzaria::Web::Form::User';
+	
+	has_field 'submit' => ( type => 'Submit', value => 'Register' );
+
+	no HTML::FormHandler::Moose;
+	__PACKAGE__->meta->make_immutable;
+	1;
+
+That was easy.  We just added a submit button and ... we're done.  The rest
+of the fields were inherited from the base class.  Now, when we want to create
+the registration form, we just create an instance of this class and
+render/validate/whatever it.  Let's make our user update form as well.
+
+	package Pizzaria::Web::Form::User::Update;
+	
+	use HTML::FormHandler::Moose;
+	extends 'Pizzaria::Web::Form::User';
+	
+	has_field 'submit' => (type => 'Submit', value => 'Update profile');
+
+	no HTML::FormHandler::Moose;
+	__PACKAGE__->meta->make_immutable;
+	1;
+
+Drop-dead simple.  We just changed name of the form (C<...::User::Update> and the
+value of the submit button, and we're done.  All of our forms can be created and
+controlled with that much ease.
+
+=head3 Rendering forms
+
+When it's time to render our forms in our controllers, we can just do this:
+
+	package Pizzaria::Web::Controller::Registration;
+	use Moose;
+	use namespace::autoclean;
+
+	use Pizzaria::Web::Form::User::Register;
+
+	sub index :Chained('/') :PathPart('register') :Args(0) {
+		my ($self, $c) = @_;
+
+		### Or you could do this in /auto or something.
+		$c->stash->{forms} = {};
+
+		### Create our registration form.
+		$c->stash->{forms}->{register} = Pizzaria::Web::Form::User::Register->new();
+
+		### Process the form with any parameters that were submitted when the page
+		### was requested.
+		$c->stash->{forms}->{register}->process(params => {%{$c->request->parameters}});
+	}
+
+	1;
+
+Then in our template (C<./root/src/registration/index.tt>:
+
+	...
+	<div id="register-new-user">
+	[% forms.register.render %]
+	</div>
+	...
+
+Which, for reference, renders our form something like this:
+
+	<div id="register-new-user">
+	<form id="form576" method="post" >
+	<table>
+		
+		<tr>
+			<td><label class="label" for="first_name">First name: </label></td>
+			<td><input type="text" name="first_name" id="first_name" value="" /></td>
+		</tr>
+		
+		<tr>
+			<td><label class="label" for="last_name">Last name: </label></td>
+			<td><input type="text" name="last_name" id="last_name" value="" /></td>
+		</tr>
+		
+		<tr>
+			<td><label class="label" for="email">Email: </label></td>
+			<td><input type="text" name="email" id="email" value="" /></td>
+		</tr>
+			
+		<tr>
+			<td><label class="label" for="password">Password: </label></td>
+			<td><input type="password" name="password" id="password" value="" /></td>
+		</tr>
+		
+		<tr>
+			<td><label class="label" for="password_confirm">Password confirm: </label></td>
+			<td><input type="password" name="password_confirm" id="password_confirm" value="" /></td>
+		</tr>
+		
+		<tr>
+			<td><input type="submit" name="submit" id="submit" value="Register" /></td>
+		</tr>
+	
+	</table>
+	</form>
+	</div>
+
+=head2 What about jQuery? (a.k.a.:  Plugins!)
+
+Ok, good for us; we can create forms easily ... but how about integration with
+jQuery?
+
+Great question.  Let's look at some ways we can spiffy-up our forms with jQuery.
+As we mentioned before, when you think jQuery, you should first think:  Plugins!
+
+jQuery's plugin community is like a decentralized CPAN.  If you want to do it,
+there's probably a plugin for it.  If you want to do it differently, leverage
+existing code to work for you.
+
+Let's take a look at some particular plugins.
+
+=head3 Unobtrusive AJAX with the C<ajaxForm> plugin
+
+If you're like me, you want lots of things to be happening with AJAX.  It lets
+you take advantage of the REST aspects of your app, lets you fire off asynchronous
+events, looks cool, and brings about world peace.  But how can we use forms 
+rendered through L<HTML::FormHandler> and L<the Template Toolkit|Template> (L<http://template-toolkit.org/>)
+to make AJAX calls?
+
+Thankfully, someone who calls himself I<malsup> thought of that and gave us a
+terrific solution:  the ajaxForm plugin (L<http://jquery.malsup.com/form/>)!
+
+First, of course, unzip the plugin into your javascript plugins directory and
+make sure it's getting loaded into the page in your template.
+
+Given the form (depicted previously), we can create a JavaScript file for the
+page in C<./root/static/javascript/register/index.tt>:
+
+	// Create an enclosure that localizes the jQuery framework into the $
+	// variable to avoid collisions with other frameworks.
+	;(function ($) {
+	
+		// Execute this function when the document has finished loading and 
+		// is ready for processing.
+		$(document).ready(function () {
+			
+			// Ajaxify our form.  Find it with a CSS 3 selector.
+			$("#register-new-user form").ajaxForm({
+				beforeSubmit: function () { /* ... */ }
+			,	success:      function () { /* ... */ }
+			})
+
+		})
+
+	})(jQuery)
+
+That's it =)  Now you can convert any form on your page to an AJAX form
+in a couple of lines of code.  For extra credit, you can use this to
+degrade gracefully in the event that the user has JavaScript disabled:
+the form still loads, but works as a regular cgi-style page submission!
+
+=head3 C<jQuery.ajax()> for REST
+
+So, you're big into REST, eh?  No problem =)  As you may know, not all
+browsers handle DELETE and PUT requests (and jQuery doesn't provide extra
+sugar for them).  With a tiny bit of footwork, though, we can side-step the
+issue.
+
+jQuery lets you submit forms via GET, POST, PUT, and DELETE.  Sugar is
+provided for GET and POST, but I don't use them to keep things uniform
+with my PUT and DELETE request.  Let's PUT a user from our registration
+form.
+
+	;(function ($) {
+		// Passing in a function is the same as passing it into $(document).ready()
+		$(function () {
+			
+			// Find the form
+			$("#register-new-user form")
+				// Hook into the "on-submit" handler.  Inside this function, "this"
+				// refers to the form element.
+				.submit(function () {
+
+					function _handleSuccess (data, textStatus, XMLHttpRequest) {
+						// ...
+					}
+
+					function _handleError (XMLHttpRequest, textStauts, errorThrown) {
+						// ...
+					}
+
+					$.ajax({
+						url:  $(this).attr("action")
+					, type: "PUT"
+					, data: $(this).serialize()
+					, dataType: "json"
+					,	success:	_handleSuccess
+					,	error:    _handleError
+					})
+				})
+		})
+	})
+
+=head3 Roll your own input tabbing
+
+That's all well and good, but what about tabbing?  Our users hate it when the
+tabbing is ordered counter-intuitively.  Tabbing should happen in the order
+of rendering on the page, right?  Easy enough:
+
+	;(function ($) {
+		$(function () {
+
+			// Start our tab indexing at 1.
+			var tab_index = 1;
+
+			// Use CSS3 selectors to get every element we want to be included 
+			// in the tab train.  Let's exclude hidden fields for obvious reasons.
+			$('input,select,button,textarea').not(':hidden')
+				.each(function () {
+					$(this).attr("tabindex", tabindex++);
+				})
+		})
+	})(jQuery)
+
+Yep; that's it.  Now your page's form elements will tab in order of rendering
+on the page.  Of course, you could make it more complex -- I'll leave it as an
+exercise to the reader to figure out how to derange his own forms.
+
+=head3 C<Datepicker> (jQuery UI core plugin)
+
+What if we want our user to register his birthday as well, so we can send him 
+a coupon for free pizza?  Easy.  Of course, go add the right fields to your
+form and the DB.  After that, we'll use jQuery UI's core plugin I<Datepicker>
+(L<http://jqueryui.com/demos/datepicker/>) to do the heavy lifting.
+
+Let's assume that your form input has the attribute C<class="date">.  We'll
+just attach the date-picker plugin to everything that's an C<input> tag with that class:
+
+	;(function ($) {
+		$(function () {
+			$("input.date").datepicker();
+		})
+	})(jQuery)
+
+All done =)  It has sensible defaults to let you navigate the calendar with
+the keyboard, supports localization, allows for hooking, and vast arrays of
+customization.  Check out the demo at (L<http://jqueryui.com/demos/datepicker/>)
+for more information.
+
+=head3 Complex Layouts with C<UI.Layout>
+
+"Oh! Oh!" you pine, "I need a complex layout with many panes and fancy things!
+Alas and alack, now I am lost!"
+
+But no!  Check out the venerable UI.Layout plugin (L<http://layout.jquery-dev.net/>)
+for jQuery.  It can help you get a multi-paned, collapsible, spectacular
+layout with relatively little markup.  It's a I<little> too involved to go
+into in this article, but look at the demos and you'll see everything you
+need to get started.  It turns out it plays nicely with Catalyst and you
+can do magic things with the stash to keep your views simple, your 
+controllers light, and your users happy.
+
+=head2 Exercises for the Reader
+
+This has been a I<very> light introduction to using jQuery with Catalyst
+applications.  The goal here is to get you past the hurdles of getting
+started with jQuery.  With a bit of imagination, you can do some really
+neat things; and the interplay between Catalyst and jQuery can be really
+productive.
+
+The real win comes when you realize that your HTML should be 
+I<semantically meaningful> without any concerns for display.  Separate your
+concerns: let Catalyst manage your data and render your pages, let 
+CSS handle your display, and let JavaScript handle your interface behaviors.
+
+Every time you find yourself violating one of those boundaries, spend the 
+extra ten minutes or two hours to find the root of the problem and solve it
+correctly, and you'll find that over time your development and debugging 
+time and costs drop, and most of your development time is on enhancements.
+
+Do the Right Thing =)
+
+=head2 Further Reading
+
+A few of suggestions:
+
+=over 
+
+=item Check out the jQuery API (L<http://api.jquery.com/>).
+
+=item Peruse the jQuery UI demos (L<http://jqueryui.com/>).
+
+=item Look at L<HTML::FormHandler> (but don't use dynamic forms =)
+
+=back
+
+Play around with it!  With Catalyst and jQuery, you can get a stable, nice
+looking app running in no time.  You already knew that.
+
+There's a chance that I'll be extending this to a more thorough and complete
+set of tutorials.  If I do, you'll be able to find them at my blog 
+(L<http://snugglepunk.blogspot.com>).
+
+=head1 Author(s)
+
+Sir Robert Burbridge <sirrobert at gmail.com>
+
+=head2 Contributors
+
+Steve Schafer
+
+=head1 Final words
+
+Merry Christmas!
+
+=cut

Deleted: trunk/examples/CatalystAdvent/root/2010/pen/TODO
===================================================================
--- trunk/examples/CatalystAdvent/root/2010/pen/TODO	2010-12-14 19:55:03 UTC (rev 13842)
+++ trunk/examples/CatalystAdvent/root/2010/pen/TODO	2010-12-14 20:26:37 UTC (rev 13843)
@@ -1,281 +0,0 @@
-MAKE SURE THAT WE INCLUDE THE VERSION NUMBER IN ALL POSTS FROM HERE ON OUT FOR NOT ONLY CATALYST BUT OTHER MODULES USED.
- - at some point I'd like to make this effective retroactively.
-
-Organising:
-  - Bogdan Lucaciu ( bogdan at sinapticode ro , zamolxes on irc)
-  - Devin Austin (devin.austin at gmail com , dhoss on irc)
-
-Article ideas (2010 Calendar):
- - facebook general application development (Getty)
- - Catalyst + Gearman (dhoss) - **DONE**
- - Catalyst + DBIx::Class::InflateColumn::FS + HTML files + X-sendfile for a simple CMS (dhoss + davewood) - **DONE**
- - Catalyst + ElasticSearch (dhoss) - **DONE**
- - DBIC::Fixtures - lukes (?)
- - twitter authentication/applications + Catalyst
- - .... as an Absolute Beginner (tm) could I put in a request for some newbie-friendly Cat-for-dummies entries? - victor from the mailing list
- - X-Sendfile/X-Accel-Redirect with support for agnostic file location retrieval (aka, file to send could be located on any number of replicated nodes etc.)
- - Form::Sensible::Reflector::DBIC + Catalyst (dhoss)
- - Test::DBIx::Class
- - jqgrid + Catalyst:Controller::REST (dhoss)
- - AWS S3, Mosso Cloudfiles, cloud storage, deployment
- - large scale application deployment, regarding replication, load balancing, etc. 
- - DBIC pretty printers, console and plack versions
- - plack middleware goodness for your Catalyst apps
- - Catalyst + DBIC + memcached - skaufman - **DONE**
- - Catalyst + jQuery theme roller - steve at matsch.com
-
-Confirmed ideas: 
- - facebook general application development (Getty)
- - Catalyst + Gearman (dhoss) ** DONE **
- - Catalyst + DBIx::Class::InflateColumn::FS + HTML files + X-sendfile for a simple CMS (dhoss + davewood)
- - Catalyst + ElasticSearch (dhoss) ** DONE **
- - twitter authentication/applications + Catalyst
- - Opsview does i18n with Catalyst (Ton Voon) - ** DONE **
-
-Ideas looking for authors
-  - Catalyst::TraitFor::Model::DBIC::Schema::Caching / DBIx::Class::Cursor::Cached
-  - Catalyst::TraitFor::Model::DBIC::Schema::Replicated / DBIx::Class::Storage::DBI::Replicated 
-  - anything not in "Confirmed Ideas"
-
-Authors:
- - Getty
- - dhoss
- - Ton Voon
- - edenc (tentative)
- - zamolxes (?)
- - frew (?)
- - hercynium
- - skaufman
- - steve at matsch.com
- - davewood
-
-Editors: 
- - jester
-
-Dates needed:
- - 1: DONE ("State of the Chainsaw" - ribasushi)
- - 2: DONE ("Catalyst + ElasticSearch" - dhoss [as a fallback, I know others want to write an article for tomorrow])
- - 3: AWS S3, Mosso Cloudfiles, cloud storage, deployment (i'll write these missing spaces - dhoss) 
- - 4: Test::DBIx::Class - dhoss
- - 5: t0m
- - 6: DONE ("Excel in Catalyst" - Caelum)
- - 7: DONE("Catalyst and Gearman" - dhoss) 
- - 8: DONE   ("Data::SearchEngine" - gphat)
- - 9: DONE  ("OpsView" - Ton Voon)
- - 10: DONE ("Data::Manager" - jshirley)      
- - 11: DONE (DBIx::Class::InflateColumn::FS and X-Sendfile) - dhoss + davewood
- - 12:      ("jQueryUI +Catalyst" - Sir and friends)
- - 13:
- - 14:
- - 15: twitter authentication/applications + Catalyst - dhoss
- - 16
- - 17
- - 18
- - 19
- - 20
- - 21
- - 22
- - 23
- - 24
-
-Plan of attack:
- - wing it
-
-
-People to annoy: 
-Catalyst-Plugin-Session-Store-FastMmap|SSCAFFIDI
-Catalyst-TraitFor-Request-PerLanguageDomains|BOBTFISH
-Catalyst-View-Haml|GARU
-Catalyst-Plugin-Params-Demoronize|DIZ
-Catalyst-Plugin-Log-Dispatch|SHOT
-Catalyst-Plugin-Session-Store-KiokuDB|MADZ
-Catalyst-Helper-Controller-DBIC-API-REST|AMIRI
-Catalyst-Plugin-Sitemap|YANICK
-Catalyst-Controller-HTML-FormFu|CFRANKS
-Catalyst-ActionRole-ExpiresHeader|AJGB
-Catalyst-Plugin-Log4perl-Simple|MOOLI
-Catalyst-Plugin-RunAfterRequest|FLORA
-Catalyst-ActionRole-BuildDBICResult|JJNAPIORK
-Catalyst-Plugin-Alarm|KARMAN
-Catalyst-Model-KiokuDB|FLORA
-Catalyst-Authentication-Credential-RPX|KENTNL
-Catalyst-Plugin-Server|JLMARTIN
-Catalyst-Plugin-HTML-Scrubber|HIDE
-Catalyst-Plugin-Server-JSONRPC|JLMARTIN
-Catalyst-Plugin-Compress-Bzip2|BOBTFISH
-Catalyst-Plugin-Compress-Zlib|BOBTFISH
-Catalyst-Authentication-Credential-OAuth|BOBTFISH
-Catalyst-Plugin-I18N-DBI|MDIETRICH
-Catalyst-View-PDF-Reuse|JONALLEN
-Catalyst-Plugin-I18N|BOBTFISH
-Catalyst-ControllerRole-Resources-Verbs|RSRCHBOY
-CatalystX-Dispatcher-AsGraph|FRANCKC
-Catalyst-Plugin-LeakTracker|NUFFIN
-Catalyst-View-TT-Alloy|PERLER
-Catalyst-Controller-Atompub|TAKERU
-Catalyst-Model-WebService-Solr|BRICAS
-Catalyst-Model-Estraier|TAKERU
-Catalyst-ActionRole-MatchRequestMethod|FLORA
-Catalyst-Plugin-Scheduler|BRICAS
-Catalyst-Controller-DBIC-Transaction|DRUOSO
-Catalyst-Plugin-Session-Store-Delegate|BOBTFISH
-Catalyst-TraitFor-Request-ProxyBase|BOBTFISH
-Catalyst-Plugin-Captcha|DIEGOK
-Catalyst-View-MicroTemplate|DMAKI
-Catalyst-Plugin-Session-Store-BerkeleyDB|FLORA
-Catalyst-TraitFor-Controller-Ping|NPEREZ
-Catalyst-Plugin-ConfigLoader-MultiState|SYBER
-Catalyst-Authentication-Realm-Adaptor|FLORA
-Catalyst-Plugin-AutoSession|ICYDEE
-CatalystX-LeakChecker|FLORA
-Catalyst-View-RRDGraph|JLMARTIN
-Catalyst-Plugin-Session-Store-DBI|FLORA
-Catalyst-Plugin-Upload-Digest|AVAR
-Catalyst-Plugin-Unicode|BOBTFISH
-Catalyst-Vew-GD-Thumbnail|UGEXE
-Catalyst-Plugin-SwiffUploaderCookieHack|TRWWW
-Catalyst-ActionRole-CheckTrailingSlash|NUCLON
-Catalyst-Authentication-Credential-HTTP|BOBTFISH
-Catalyst-Plugin-ConfigLoader-Remote|JSHIRLEY
-Catalyst-TraitFor-Request-XMLHttpRequest|FLORA
-Catalyst-Plugin-Assets|RKRIMEN
-CatalystX-CRUD-View-Excel|KARMAN
-CatalystX-CRUD-Controller-RHTMLO|KARMAN
-Catalyst-Plugin-Session-FastMmap|BOBTFISH
-Catalyst-Plugin-LogWarnings|BOBTFISH
-Catalyst-Plugin-Cache-Memcached|BOBTFISH
-Catalyst-Model-CDBI|BOBTFISH
-Catalyst-TraitFor-Request-Params-Hashed|CUB
-Catalyst-TraitFor-Model-DBIC-Shortcut|CUB
-CatalystX-Profile|CYCLES
-Catalyst-Plugin-Devel-ModuleVersions|ANDREMAR
-Catalyst-Plugin-DebugCookie|JGOULAH
-Catalyst-Plugin-AutoRestart|JGOULAH
-Catalyst-View-JavaScript|PERLER
-Catalyst-Plugin-SubRequest|BOBTFISH
-Catalyst-Plugin-UploadProgress|MRAMBERG
-Catalyst-Plugin-Authentication|FLORA
-Catalyst-Plugin-Session-PerUser|BOBTFISH
-Catalyst-View-REST-YAML|BOBTFISH
-Catalyst-View-REST-XML|BOBTFISH
-Catalyst-Plugin-Textile|BOBTFISH
-Catalyst-Plugin-Pluggable|BOBTFISH
-Catalyst-Plugin-HTML-Widget|BOBTFISH
-Catalyst-Plugin-Ajax|BOBTFISH
-Catalyst-TraitFor-Controller-Breadcrumb-Followed|ICYDEE
-Catalyst-TraitFor-Model-DBIC-Schema-QueryLog|FAYLAND
-catalyst-traitfor-controller-breadcrumb-followed|ICYDEE
-Catalyst-Controller-RateLimit|GUGU
-Catalyst-Plugin-Snippets|BOBTFISH
-Catalyst-Helper-View-TT-Bootstrap-YUI|JSHIRLEY
-Catalyst-Plugin-AccessLog|ARODLAND
-Catalyst-Model-Bitcoin|PKAROUKIN
-Catalyst-Manual|ZARQUON
-Catalyst-Authentication-Credential-OpenID|ASHLEY
-Catalyst-Plugin-Log-Log4perl|PRAVUS
-Catalyst-Plugin-Session|BOBTFISH
-Catalyst-Plugin-Session-State-URI|BOBTFISH
-Catalyst-Plugin-Log-Handler|PEPE
-Catalyst-ActionRole-NotCacheableHeaders|AJGB
-Catalyst-TraitFor-Model-DBIC-Schema-QueryLog-AdoptPlack|JJNAPIORK
-Catalyst-Plugin-CustomErrorMessage|JKUTEJ
-CatalystX-Component-Traits|BOBTFISH
-Catalyst-Authentication-Credential-YubiKey|TJC
-Catalyst-Model-LDAP-FromAuthentication|BOBTFISH
-CatalystX-FacebookURI|NACHBAUR
-Catalyst-Plugin-Params-Nested|BOBTFISH
-Catalyst-Plugin-FormValidator-Simple|DHOSS
-Catalyst-Controller-POD|PERLER
-Catalyst-Example-InstantCRUD|WREIS
-Catalyst-TraitFor-Model-DBIC-Schema-ConnectInfo-Several|CUB
-CatalystX-Controller-Pluggable|DHOUSTON
-Catalyst-Engine-Stomp|PMOONEY
-Catalyst-Plugin-Session-Store-MongoDB|SVOELKEL
-Catalyst-Plugin-Cache|BOBTFISH
-Catalyst-Plugin-AutoCRUD|OLIVER
-Catalyst-Plugin-ErrorCatcher-ActiveMQ-Stomp|JTANG
-CatalystX-CMS|KARMAN
-Catalyst-Plugin-Singleton|MRAMBERG
-CatalystX-Debug-ResponseHeaders|BOBTFISH
-CatalystX-Debug-RequestHeaders|BOBTFISH
-Catalyst-Plugin-Compress|XINMING
-Catalyst-Model-Xapian|MRAMBERG
-Catalyst-Model-MenuGrinder|ARODLAND
-Catalyst-TraitFor-Controller-DBIC-DoesPaging|FREW
-Catalyst-Plugin-Static-Simple-ByClass|KARMAN
-Catalyst-Model-SWISH|KARMAN
-Catalyst-Plugin-DBIC-Schema-Profiler|YAMAMOTO
-Catalyst-Plugin-ErrorCatcher|CHISEL
-Catalyst-View-GD-Barcode|YANA
-Catalyst-Model-MultiAdaptor|KITANO
-Catalyst-Authentication-Credential-RemoteHTTP|NIGELM
-Catalyst-Action-RenderView-ErrorHandler|ANDREMAR
-CatalystX-Widget-Paginator|LONERR
-Catalyst-Model-Facebook|GETTY
-Catalyst-Plugin-I18N-PathPrefix|MENDEL
-Catalyst-View-JavaScript-Minifier-XS|FREW
-Catalyst-Controller-reCAPTCHA|ZARQUON
-Catalyst-Controller-ActionRole|FLORA
-Catalyst-Plugin-ConfigLoader|BRICAS
-Catalyst-Controller-LeakTracker|WREIS
-Catalyst-Plugin-Bread-Board|FLORA
-Catalyst-Authentication-Credential-CAS|PRAVUS
-Catalyst-Controller-Combine|WKI
-CatalystX-Controller-Sugar-ActionPack|JHTHORSEN
-Catalyst-Plugin-ConfigLoader-Environment|DHOSS
-Catalyst-Controller-SOAP|DRUOSO
-Catalyst-Model-SOAP|DRUOSO
-CatalystX-Plugin-Blurb|ASHLEY
-Catalyst-Controller-MovableType|OKKO
-Catalyst-TraitFor-Controller-LocaleSelect|DIEGOK
-Catalyst-TraitFor-Controller-jQuery-jqGrid|ICYDEE
-Catalyst-Model-Memcached|CATONE
-Catalyst-Plugin-Static-Simple|MSTROUT
-CatalystX-Test-Recorder|PERLER
-Catalyst-Plugin-Widget|LONERR
-Catalyst-Plugin-PageCache|TIMB
-CatalystX-Declare|JJNAPIORK
-Catalyst-Engine-Apache|FLORA
-Catalyst-Authentication-Store-DBI-ButMaintained|ECARROLL
-Catalyst-View-Tenjin|IDOPEREL
-Catalyst-Model-Adaptor|BOBTFISH
-Catalyst-Engine-PSGI|MIYAGAWA
-Catalyst-Helper-AuthDBIC|ZARQUON
-Catalyst-Devel|BOBTFISH
-Catalyst-Model-Sedna|DRUOSO
-Catalyst-View-Excel-Template-Plus|RBO
-Catalyst-ActionRole-RequireSSL|ELLIOTT
-Catalyst-View-HTML-Zoom|CYCLES
-Catalyst-Model-DBI|ALEXP
-CatalystX-CRUD-YUI|KARMAN
-Catalyst-Authentication-Store-LDAP-AD-Class|FILIN
-CatalystX-I18N|MAROS
-Catalyst-View-HTML-Mason|RBUELS
-Catalyst-View-JSON|MIYAGAWA
-Catalyst-Controller-WrapCGI|RKITOVER
-Catalyst-Plugin-Unicode-Encoding|BOBTFISH
-CatalystX-Controller-Sugar|JHTHORSEN
-Catalyst-View-Component-SubInclude|BOBTFISH
-CatalystX-CRUD|KARMAN
-Catalyst-View-ByCode|WKI
-Catalyst-Authentication-Store-DBIx-Class|BOBTFISH
-Catalyst-Model-MongoDB|GETTY
-Catalyst-View-TT|ABRAXXA
-Catalyst-Authentication-Store-LDAP|BOBTFISH
-Catalyst-Controller-DirectoryDispatch|AGORMAN
-CatalystX-DebugFilter|BPHILLIPS
-CatalystX-Features|RODRIGO
-CatalystX-AppBuilder|DMAKI
-Catalyst-Action-REST|BOBTFISH
-CatalystX-SimpleLogin|BOBTFISH
-Catalyst-View-Xslate|DMAKI
-Catalyst-Controller-DBIC-API|ABRAXXA
-Catalyst-Model-DBIC-Schema|RKITOVER
-Catalyst-View-GD-Thumbnail|UGEXE
-Catalyst-Plugin-FormValidator|DHOSS
-Catalyst-Example-InstantCRUDStylish|HERNAN
-CatalystX-ExtJS|PERLER
-Catalyst-Model-REST|KAARE
-Catalyst-Runtime|BOBTFISH
-Catalyst-View-Email|DHOSS
- 




More information about the Catalyst-commits mailing list