[Catalyst-commits] r8943 - trunk/examples/CatalystAdvent/root/2008

jester at dev.catalyst.perl.org jester at dev.catalyst.perl.org
Thu Dec 25 12:36:41 GMT 2008


Author: jester
Date: 2008-12-25 12:36:41 +0000 (Thu, 25 Dec 2008)
New Revision: 8943

Modified:
   trunk/examples/CatalystAdvent/root/2008/24.pod
Log:
edits; more needed

Modified: trunk/examples/CatalystAdvent/root/2008/24.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2008/24.pod	2008-12-24 14:36:00 UTC (rev 8942)
+++ trunk/examples/CatalystAdvent/root/2008/24.pod	2008-12-25 12:36:41 UTC (rev 8943)
@@ -1,18 +1,15 @@
 =head1 Catalyst AJAX With MochiKit
 
-In this advent calendar I want to show how MochiKit
+In this Advent entry I want to show how MochiKit
 (L<http://www.mochikit.com>) can be used to add AJAX (or my favorite
-under used buzzword "Web 2.0") functionality to the Catalyst Tutorial
+under-used buzzword "Web 2.0") functionality to the Catalyst Tutorial
 on CPAN.
 
 =head1 What You Need
 
-You need the Tutorial example app Part 4 (Basic CRUD) which can be
+You need the Tutorial example app Part 4 (Basic CRUD), which can be
 downloaded from
-L<http://www.catalystframework.org/calendar/static/2008/mochikit/MyApp_Part4.tgz>. Important
-to note that while writing this article the examples in the tutorial
-changed so this download is of the older example than the one online
-now.
+L<http://www.catalystframework.org/calendar/static/2008/mochikit/MyApp_Part4.tgz>. Important: during the course of writing this article, the examples in the tutorial changed, so this download is of the older version than the one currently online.
 
 You need the MochiKit JavaScript Library which can be downloaded from
 L<http://www.mochikit.com/dist/MochiKit-1.4.2.zip>. This zip file
@@ -20,24 +17,24 @@
 
 =head1 Why MochiKit?
 
-Without going into JavaScript Library wars MochiKit has some great
+Without going into JavaScript library wars, MochiKit has some great
 features which should make it a candidate for any project that is
 going to need a lot of JavaScript development. It will save you from
 writing without controlling you. Some of the main reasons I think it
-should be considered is:
+should be considered are:
 
 =over
 
 =item *
 
-Lightweight and the various functional libraries can be cut out if not
+Lightweight; the various functional libraries can be cut out if not
 needed
 
 =item *
 
 Does not alter JavaScript to the point where its not JavaScript
-anymore like some libraries. I find it has the Perl mentality of
-letting you do things anyway you want and can be used with other UI
+anymore, like some libraries. I find it has the Perl mentality of
+letting you do things any way you want, and can be used with other UI
 libraries
 
 =item *
@@ -47,21 +44,21 @@
 =item *
 
 It integrates well with prebuilt applications as we will see in this
-example. You don't need to re-write the whole UI in some other
-libraries widgets to get good functionality out of it
+example. You don't need to re-write the whole UI, as in some other
+libraries' widgets, to get good functionality out of it
 
 =item *
 
-Comes with a non-browser dependant JavaScript debugging console in
+Comes with a non-browser-dependent JavaScript debugging console in
 case you're not using something like FireBug
 (L<http://getfirebug.com/>) (which is highly recommended in any case)
 
 =back
 
-=head1 Now Lets Begin
+=head1 Now Let's Begin
 
-Ok so first thing is first download the Tutorial Part 4 and extract it
-where you want it in my case its on my Desktop.
+The first thing is to download the Tutorial Part 4 and extract it
+where you want it; in my case, it's on my Desktop.
 
 =begin pod::xhtml
 
@@ -69,7 +66,7 @@
 
 =end pod::xhtml
 
-Ok now lets start the server and make sure its working.
+Now, let's start the server and make sure it's working.
 
 =begin pod::xhtml
 
@@ -77,9 +74,9 @@
 
 =end pod::xhtml
 
-Ok now lets browse to our books controller to the list action which
-for me is L<http://localhost:3000/books/list> and you should see the
-default data from the downloaded example like the image below.
+Now, let's browse to our books controller's list action at
+L<http://localhost:3000/books/list>, and you should see the default data
+from the downloaded example like the image below.
 
 =begin pod::xhtml
 
@@ -87,17 +84,17 @@
 
 =end pod::xhtml
 
-This is where I will be adding the AJAX functionality. I think it
-would be sooooo Web 2.0'ish if we could create, delete, and modify the
+This is where we will be adding the AJAX functionality. I think it
+would be sooooo Web 2.0-ish if we could create, delete, and modify the
 books and have the UI updated without a page refresh. However, I will only be
 showing creates.
 
-Lets load the MochiKit library into our templates so its loaded on all
-pages. To do that lets first create a js directory inside of
-root/static/ to hold our js files. Then lets copy the packed (white
-space removed) MochiKit file which includes all the libraries in one
-file for the sake of simplicity. In a production enviorement you will
-probably only want to load the nessasary libraries.
+Let's load the MochiKit library into our templates so it's loaded on all
+pages. To do that, first create a js directory inside of
+root/static/ to hold our JaveScript files. Then let's copy the packed (white
+space removed) MochiKit file, which includes all the libraries in one
+file for the sake of simplicity. In a production environment you will
+probably only want to load the necessary libraries.
 
 =begin pod::xhtml
 
@@ -105,32 +102,34 @@
 
 =end pod::xhtml
 
-Now lets modify the current MyApp/root/lib/site/html file to include
+Now let's modify the current MyApp/root/lib/site/html file to include
 the MochiKit library on all pages. Just add the following line after
 the css section in the file.
 
     <script type="text/javascript" src="[% Catalyst.uri_for('/static/js/MochiKit.js') %]"></script>
 
 Now make sure that when you restart your server and reload the
-L<http://localhost:3000/books/list> page the MochiKit library file is
-being loaded on the page.  You can do this by browsing to
-L<http://localhost:3000/static/js/MochiKit.js'>
+L<http://localhost:3000/books/list> page, the MochiKit library file is
+being loaded on the page. You can do this by browsing to
+L<http://localhost:3000/static/js/MochiKit.js>
 
 =head1 So Here Is The Plan
 
-Lets add the ability to create as many books as we want without
-needing to refresh. Just for fun lets also do some simple input
-validation. The basic idea is we will have some input taken from user,
-then posted to Catalyst by JavaScript, Catalyst will process and give
-us standarized response, and our JavaScript will process the response
-and update the page as needed. First thing is first lets create the
-needed UI elements in the template. I think all we would need is an
-empty Title, Rating, and Author ID text field. Change the top of the
-table in the template MyApp/root/src/books/list.tt2 to include a
-thead, tbody, and an id for the tbody. MochiKit has some DOM Coersion
-rules and requires tbody in tables if we want to manipulate them. Add
-the following to the bottom of MyApp/root/src/books/list.tt2.
+Let's add the ability to create as many books as we want without
+needing to refresh. Just for fun, let's also do some simple input
+validation. The basic idea is we will have some input taken from the user,
+then posted to Catalyst by JavaScript. Catalyst will process and give
+us a standarized response, and our JavaScript will process the response
+and update the page as needed. 
 
+First thing is first: let's create the needed UI elements in the
+template. I think all we would need is an empty Title, Rating, and
+Author ID text field. Change the top of the table in the template
+MyApp/root/src/books/list.tt2 to include a C<thead>, C<tbody>, and an
+C<id> for the C<tbody>. MochiKit has some DOM Coercion rules and requires
+C<tbody> in tables if we want to manipulate them. Add the following to the
+bottom of MyApp/root/src/books/list.tt2:
+
     <table>
     <thead>
     <tr><td>Title</td><td>Rating</td><td>Author(s)</td><td>Links</td></tr>
@@ -149,20 +148,20 @@
     <input type="button" name="add" value="add" id="add_book">
     <script type="text/javascript" src="[% Catalyst.uri_for('/static/js/list.js') %]"></script>
 
-We also want to edit the MyApp/root/lib/site/layout file and add an id
-that we can reference for both span elements so that we can update
-them live. We will also remove the stash references so that it only
-gets updated via JavaScript and not through the template processing.
+We also want to edit the C<MyApp/root/lib/site/layout> file and add an
+id that we can reference for both span elements, so that we can update
+them live. We will also remove the stash references so that it only gets
+updated via JavaScript, and not through the template processing.
 
     <span class="message" id="message"></span>
     <span class="error" id="error"></span>
 
-Now we are ready to start writing the JavaScript for the page. Lets
-create a file MyApp/root/static/js/list.js. For this example first
-thing we want to do is create variables that will be references to
+Now we are ready to start writing the JavaScript for the page. Let's
+create a file C<MyApp/root/static/js/list.js>. For this example, the
+first thing we want to do is create variables that will be references to
 things we know we need.
 
-    //Creates MochiKit logging pane. Remove true if you want it popped out in its own window
+    //Creates MochiKit logging pane. Remove "true" if you want it popped out in its own window
     createLoggingPane(true);
 
     var message = getElement('message');
@@ -173,32 +172,34 @@
     var author_id = getElement('author_id');
     var add_book = getElement('add_book');
 
-If you are already pretty familiar with JavaScript you probably
+If you are already pretty familiar with JavaScript, you probably
 noticed I am using a getElement() instead of getElementById() which is
 the standard JavaScript function for getting a handle on an
 element. This getElement() function is a MochiKit helper function
-which saves you 4 keystrokes!!! No seriously its really useful because
+which saves you 4 keystrokes!!! Seriously, it's really useful because
 it does some checks on input and is more flexible than the standard
-getElementById(). Remember that MochiKit logging console I was talking
-about earlier well the createLoggingPane(true) call creates this
-window at the bottom of the page if you want it as a popup window just
-call createLoggingPane() without the true.
+getElementById(). Remember that the MochiKit logging console I was talking
+about earlier? The C<createLoggingPane(true)> call creates this
+window at the bottom of the page; if you want it as a popup window,just
+call C<createLoggingPane()> without the "true".
 
-The next thing we want to do is when the Add button is clicked we want
-to read the input and submit it but I want to explain a few things
-first. With MochiKit you can use the typical event handlers like
-onClick, onMouseUp, etc. However MochiKit has a better cross browser
-event handling system they call Signals
+The next thing we want to do is to read the input and submit it when the
+Add button is clicked.
+
+But I want to explain a few things first. With MochiKit you can use the
+typical event handlers like onClick, onMouseUp, etc. However MochiKit
+has a better cross-browser event handling system they call Signals
 (L<http://www.mochikit.com/doc/html/MochiKit/Signal.html>) which does
-not leak memory however you can't have both. Oh yeah and there is a
-price to pay... and that is load events are not supported at the same
-time Signals are. The only real side affect of that is you can't
-create a JavaScript function that gets called by C<<body
-onload="my_javascript_function()">> which means you will need to have
-that called at the bottom of the page or after you know things are
-loaded. Trust me its worth going with the signals. Ok so add the
-following lines to your list.js file.
+not leak memory. However you can't have both. And there is a price to
+pay: load events are not supported at the same time Signals are. The
+only real side affect of that is you can't create a JavaScript function
+that gets called by C<<body onload="my_javascript_function()">> which
+means you will need to have that called at the bottom of the page or
+after you know things are loaded. Trust me, it's worth going with the
+signals.
 
+So, add the following lines to your list.js file:
+
     connect
     (
         add_book,
@@ -213,18 +214,18 @@
     );
 
 Restart the server and refresh the page and you should see the logging
-window at the bottom and when you click on the add button you should
+window at the bottom, and when you click on the add button you should
 see the C<"I have been clicked"> text and whatever values are in the
-input text fields now tell me thats not cool!
+input text fields. Now tell me that's not cool!
 
-Ok now to explain some more MochiKit before we add our AJAX
+Now to explain some more MochiKit before we add our AJAX
 stuff. MochiKit uses an Async
 (L<http://www.mochikit.com/doc/html/MochiKit/Async.html>) framework
-which has defferred objects for Async calls. Defererred objects
+which has deferred objects for asynchronous calls. Defererred objects
 basically have callbacks and other associated properties. You can add
-Async functionality to basically anything with MochiKit but in this
+Async functionality to almost anything with MochiKit but in this
 case it will be for our XMLHttpRequests. Deferred objects are cool and
-very powerful if you want to really add a lot of flexibility to your
+very powerful if you want to add a lot of flexibility to your
 application. You can cancel deferred objects, set errors, have error
 callback functions, etc. Add the following lines of code to your
 list.js under the log() calls.
@@ -237,7 +238,7 @@
         author_id: author_id.value
     };
 
-    //Calling MochiKits doXHR which makes XMLHttpRequests painless
+    //Calling MochiKit's doXHR which makes XMLHttpRequests painless
     var d = doXHR
     (
         '/books/create_do',
@@ -248,17 +249,17 @@
         }
     );
 
-We created an object named params to hold our arguments that we post
-to our Catalyst app. Then we call the MochiKit function doXHR
-(L<http://www.mochikit.com/doc/html/MochiKit/Async.html#fn-doxhr>)
+We created an object named C<params> to hold our arguments that we post
+to our Catalyst app. Then we call the MochiKit function C<doXHR>
+(L<http://www.mochikit.com/doc/html/MochiKit/Async.html#fn-doxhr>),
 which creates a deferred object and returns that deferred object which
 we call 'd'. Then the params object is converted to a query string
-that is URL encoded using the MochiKit function queryString(). Another
+that is URL encoded using the MochiKit function C<queryString()>. Another
 thing you might notice is the URL the post is happening to is
-/books/create_do which means we need to create that action. Before we
-can create that action however we need to do a few things like setup a
+C</books/create_do> which means we need to create that action. Before we
+can create that action, however, we need to do a few things, like setup a
 Catalyst view for JSON and configure that. We will be using
-L<Catalyst::View::JSON> so make sure its installed before you
+L<Catalyst::View::JSON> so make sure it's installed before you
 continue.
 
 =begin html
@@ -267,12 +268,11 @@
 
 =end html
 
-Once we created our view now lets configure it. Its good practice to
-set a default view once more than one view has been added to a
-Catalyst app. In our case we want the default to be TT. We also want
-to set the json_driver to L<JSON::XS> and we want to only expose the
-named 'json' hash in the stash. This is how I modified my config call
-in MyApp/lib/MyApp.pm.
+Once we created our view, let's configure it. It's good practice to set
+a default view once a Catalyst app has more than one view. In our case
+we want the default to be TT. We also want to set the json_driver to
+L<JSON::XS> and we want to only expose the named 'json' hash in the
+stash. This is how I modified my config call in MyApp/lib/MyApp.pm.
 
     __PACKAGE__->config
     (
@@ -285,7 +285,7 @@
         default_view => 'TT'
     );
 
-Finally here is my /books/create_do action.
+Finally, here is my C</books/create_do> action.
 
     sub create_do : Local {
         my ($self, $c) = @_;
@@ -368,37 +368,37 @@
 
 I am not going to go into details here about what every line of code
 does but I am going to point out the specific things I am doing for an
-AJAX'y JSON response. Notice that I define my $ret variable with some
+AJAX-y JSON response. Notice that I define my C<$ret> variable with some
 default values. This is important because on the JavaScript side we
 need to add code that will handle this response and we need to have
 some clear indications if things worked. So having standard values are
-good practices just trusting that the XMLHttpRequest returned a 200 is
-not very good in cases where your processing data.
+good practices; just trusting that the XMLHttpRequest returned a 200 is
+not very good in cases where you are processing data.
 
 Now we just need to update our JavaScript code to handle the response
 and manipulate the DOM. In our case our JavaScript code does what our
-TT templates do and that is read from a defined data structure and
+TT templates do: read from a defined data structure and
 render our page. Below is the complete JavaScript file. Notice after
-our doXHR() call we add a callback to that deferred object. Without
-creating this callback once the XMLHttpRequest is complete nothing
-will happen but in our case we need to process that returned data so
-we create an annonomous function to handle that data. We call
-MochiKits evalJSONRequest() and that takes care of creating our
+our C<doXHR()> call we add a callback to that deferred object. Without
+creating this callback, once the XMLHttpRequest is complete nothing
+will happen, but in our case we need to process that returned data so
+we create an anonymous function to handle that data. We call
+MochiKit's C<evalJSONRequest()> and that takes care of creating our
 JavaScript object. The advantage here is that you don't need to do
 anything hard or annoying like parsing values out or stripping
-characters your working with a Object with a structure you can access
+characters: you're working with a Object with a structure you can access
 in very easy and defined ways. Doing things this way makes JavaScript
-painless and to me feels very Perl'ish. You can see in the code I
-check to make sure status is Successful and if it is I start creating
+painless and to me feels very Perlish. You can see in the code I
+check to make sure status is Successful, and if it is I start creating
 DOM Elements and storing them into variables that I can reference
-later. I usually wouldn't store them I would probably just create that
-whole structure annonomously but I purposely did different things so
+later. I usually wouldn't store them, I would probably just create that
+whole structure annonomously, but I purposely did different things so
 that you could see some different examples. You can see with MochiKit
 creating and manipulating the DOM on the fly is a piece of cake. All
 those MochiKit calls like A(), TD(), TR(), etc are Partials which I
 will explain below.
 
-    //Creates MochiKit logging pane. Remove true if you want it popped out in its own window
+    //Creates MochiKit logging pane. Remove "true" if you want it popped out in its own window
     createLoggingPane(true);
     
     var message = getElement('message');
@@ -502,11 +502,11 @@
                             ]
                         );
                         
-                        //you can log this to firebug and actually inspect the dom
+                        //you can log this to FireBug and actually inspect the dom
                         //its like a hackish Data::Dump::dump() for JavaScript
                         console.log(tr_book);
                         
-                        //Calling MochiKits appendChildNodes() to only the fly update the DOM
+                        //Calling MochiKit's appendChildNodes() to only the fly update the DOM
                         appendChildNodes(list_body, [tr_book]);
                     }
                     else
@@ -529,9 +529,36 @@
         }
     );
 
-Partials (L<http://www.mochikit.com/doc/html/MochiKit/Base.html#fn-partial>) are really cool and are one of the reasons why MochiKit can save a lot of coding. Partials are basically wrappers of partially applied functions. This is really useful for creating re-usable functions that could be wrapping several functions well you might argue that "Why wouldn't I just call functions with parameters?" well you can if you want but a Partial is meant to wrap that for you. In the example above I created a simple function for updating the messages to the user. Now each time I call that function I could do update_user("message",resp.status); Or I can create a partially applied function for both "message" and "error" so that I can call them and just pass in One argument like u_message(resp.status); Another good use for Partials is if your creating a lot of UI components. For example if you want to create a UI component you will always re-use that wraps a C<E<lt>aE<gt>E<lt>E<sol>aE<gt>> inside of a DIV with certain style attributes set a Partial would be perfect candidate to save you a lot of typing each time you created that.
+Partials
+(L<http://www.mochikit.com/doc/html/MochiKit/Base.html#fn-partial>) are
+really cool and are one of the reasons why MochiKit can save a lot of
+coding. Partials are basically wrappers of partially applied
+functions. This is really useful for creating re-usable functions that
+could be wrapping several functions. You might argue, "Why
+wouldn't I just call functions with parameters?" Well you can if you
+want, but a Partial is meant to wrap that for you. In the example above I
+created a simple function for updating the messages to the user. Now
+each time I call that function I could do
+update_user("message",resp.status); or I can create a partially applied
+function for both "message" and "error" so that I can call them and just
+pass in one argument like C<u_message(resp.status)>. Another good use for
+Partials is if you're creating a lot of UI components. For example, if you
+want to create a UI component, you will always re-use that wraps a
+C<E<lt>aE<gt>E<lt>E<sol>aE<gt>> inside of a DIV with certain style
+attributes set a Partial would be perfect candidate to save you a lot of
+typing each time you created that.
 
-Before I finish I would just like to show off a few benefits of FireBug for this type of AJAX Development. Below I show screenshots of FireBug console window after I click the Add button. FireBug logs XMLHttpRequests in the console window by default. It shows the HTTP Method (POST, GET), the URL, parameters passed, and the response from the server. This is really useful while you are in the development process because you can see the parameters passed to the server from the clients point of view. Its also very useful to see the raw response from the server to see if the data structure your expecting is really being returned or not. Of course if needed you can also see the request and response headers. 
+Before I finish I would just like to show off a few benefits of FireBug
+for this type of AJAX development. Below I show screenshots of FireBug
+console window after I click the Add button. FireBug logs
+XMLHttpRequests in the console window by default. It shows the HTTP
+Method (POST, GET), the URL, parameters passed, and the response from
+the server. This is really useful while you are in the development
+process because you can see the parameters passed to the server from the
+client's point of view. Its also very useful to see the raw response from
+the server to see if the data structure you're expecting is really being
+returned or not. Of course if needed you can also see the request and
+response headers.
 
 =begin html
 
@@ -545,7 +572,20 @@
 
 =end html
 
-Another FireBug feature I wanted to show is the easy ability to log DOM elements to the console window so you can inspect them further. With FireBug enabled you can right click any element and select "Inspect Element" and view the element with its HTML, CSS, and DOM properties. What's even cooler is you can further modify any of those aforementioned properties on the fly and see the result live! In the screenshot above you can see C<Object status=Successful error=Object data=Object> in the console window. This is because in my list.js I have console.log(resp) being called in my callback for my deferred object. When you call console.log() and pass in an object you can inspect that object in the DOM. This is very useful if you want to inspect what type of data structure an object is and what values it contains. You can do this for any DOM element or variable. The below screenshot shows the result of our "resp" object.
+Another FireBug feature I wanted to show is the easy ability to log DOM
+elements to the console window so you can inspect them further. With
+FireBug enabled, you can right-click any element and select "Inspect
+Element" and view the element with its HTML, CSS, and DOM
+properties. What's even cooler is that you can further modify any of
+those aforementioned properties on the fly and see the result live! In
+the screenshot above you can see C<Object status=Successful error=Object
+data=Object> in the console window. This is because in my list.js I have
+console.log(resp) being called in my callback for my deferred
+object. When you call console.log() and pass in an object you can
+inspect that object in the DOM. This is very useful if you want to
+inspect what type of data structure an object is and what values it
+contains. You can do this for any DOM element or variable. The
+screenshot below shows the result of our "resp" object:
 
 =begin html
 
@@ -553,7 +593,14 @@
 
 =end html
 
-The final FireBug cool feature I wanted to show is the JavaScript console. This console allows full interaction with your page on the fly. All your functions and libraries that are loaded on the page are accessible via FireBug's console. I usually start prototyping my JavaScript code in FireBug's console window before I put it into my JS file because its faster and doesn't need to have the page refreshed to load the updated JS file. Below you see a screenshot of calling our partial u_message() function from the console.
+The final FireBug cool feature I wanted to show is the JavaScript
+console. This console allows full interaction with your page on the
+fly. All your functions and libraries that are loaded on the page are
+accessible via FireBug's console. I usually start prototyping my
+JavaScript code in FireBug's console window before I put it into my JS
+file because it's faster and doesn't need to have the page refreshed to
+load the updated JS file. Below you see a screenshot of calling our
+partial C<u_message()> function from the console.
 
 =begin html
 
@@ -565,4 +612,4 @@
 
 =head1 Author
 
-Ali Mesdaq (amesdaq at websense.com), is a Sr. Security Researcher with Websense Security Labs (L<http://securitylabs.websense.com/>).
+Ali Mesdaq (amesdaq at websense.com), is a Senior Security Researcher with Websense Security Labs (L<http://securitylabs.websense.com/>).




More information about the Catalyst-commits mailing list