Mason Components for AJAX
David P. Bushong
AvantGo/iAnywhere, Inc.
Overview
 - Know Your Tools
- Don't Repeat Yourself
- Survive JavaScriptlessness
- Get Organized
- Be Secure
 
What is Mason?
Mason is a Perl app-server
You can embed Perl code in your HTML and build OO-style components which
inherit and extend functional components of your site.
Mason: Embed Perl in HTML
<html><body>
What do you get when you multiply six by nine?
<br/>
<% 6 * 7 %>
</body></html>
 
Mason: Calling Components
From inside HTML: 
<& some-comp, arg1 => 'value', arg2 => 'value' &>
From inside a Perl block: 
$m->comp('some-comp', arg1 => 'value', arg2 => 'value'
On a line by itself: 
<ul>
% for my $row (@rows) {
 <li><% $row->{name} |h %></li>
% }
</ul>
 
Mason JavaScript Escaping
Mason makes HTML and URI encoding easy with 
|h and 
|u; 
make it equally easy for JavaScript with 
|j:
  $m->interp->set_escape(j => sub {
    my $str = shift;
    $str =~ s/\\/\\\\/g;
    $str =~ s/'/\\'/g;
    $str =~ s/\n/\\n/g;
    $str
  });
 
What is AJAX?
Asynchronous JavaScript And XML
- 
 Basically, making a call to XMLHttpRequest() from the JavaScript on 
 an already-loaded page so as to send, receive (or both) information, usually
 resulting in an update of some part of the page without reloading the whole
 page.
- 
 Data is sent using XMLHttpRequest() via GET or POST, usually URI 
 encoded.
 
AJAX 101
First and foremost, don't reinvent the wheel: use prototype.js or a 
similar JavaScript framework
 - new Ajax.Request(url, { opts });
- { key: 'value', key2: 'value2' } syntax
- function () { ... } syntax
- $('id_of_element')
 
Receiving AJAX Data
Data can be received and used a number of ways:
 
Receiving JSON
JavaScript Over Network (JSON)
 - e.g.: { foo: [1, 2, 3], bar: 'hello' }
- Great for getting back a data structure you can easily access
 
Receiving XML
XML (the X in AJAX)
 - e.g. <results><foo>42</foo><bar id="42" 
   /></results>
- Great for getting back a data tree you can (fairly) easily navigate.
- Easier to navigate with XPath extensions showing up in some browsers
- Only option for back-end server you don't control (tie-in to REST Services)
   Can be transformed with XSLT to produce HTML snippets.
 
Receiving HTML
An HTML snippet to insert/replace into page using innerHTML
 - e.g. <div><ul><li>foo</li><li>bar</li></ul></div>
- Saves a lot of DOM coding to build new HTML chunks
- Easiest for appending/replacing inline
- Since server produces all HTML, avoids duplicated functionality
 
Overview
 - Know Your Tools
- Don't Repeat Yourself
- Survive JavaScriptlessness
- Get Organized
- Be Secure
 
Don't Repeat Yourself
Avoiding duplication of code is a very, very good thing (D.R.Y.)
There are many tools and techniques available to avoid duplication in web 
development:
 - Use CSS: code your style in one place, reuse it all over.  Even within your
  CSS stylesheets you can avoid duplication through the use of grouped class/id
  assignments of shared style elements
- Put data-related functions used in more than one place in Perl modules
- Put reused HTML snippets into Mason components.  Even when there's no
  reuse, this isn't a bad idea to split up the design a bit
 
Reusing Existing Code
 - 
  Since you can detect an XMLHTTPRequest on the server side, you may be able to
  reuse your existing action receiver, depending on how it is designed.
 
- 
  The same component you use to render a part of the page in full-page 
  rendering mode can be used to render a newly created HTML chunk you're 
  inserting with .innerHTML
 
- 
  And since we're reusing existing code wherever possible, that'll make it easy
  to support JavaScriptless environments:
 
 
Overview
 - Know Your Tools
- Don't Repeat Yourself
- Survive JavaScriptlessness
- Get Organized
- Be Secure
 
Survive JavaScriptlessness
Modern websites should perform gracefully without JavaScript
 - Important for accessibility
- Makes them more scriptable, which makes testing easier
- Provides broader browser support
- Lets clients fall back to basic functionality should your JavaScript
  explode for some reason (gasp!)
 
HTML for !JavaScript
 - Provide real href and action attributes for AJAXified forms and links
- Return false in the onclick and onsubmit handlers.
- If the JavaScript doesn't or can't run, the "old-fashioned" behavior will 
     run.
 
Perl for !JavaScript
 - 
  Trap AJAX-specific request parameters or headers, and provide minimally
  different behavior in an existing/shared action handler to process the 
  results.
 
- 
  Often the AJAX-specific behavior is as simple as not redirecting back to
  the previous page or emitting the newly minted HTML chunk
 
 
Overview
 - Know Your Tools
- Don't Repeat Yourself
- Survive JavaScriptlessness
- Get Organized
- Be Secure
 
Cliché Example
 - We're building... a blog!
- You can post a new entry and delete an old one
- Since we don't want to repeat ourselves, let's make sure the JavaScript
  and the HTML aren't re-rendering the same page snippets
 
Layout Overview
Directory layout:
 action/ -- HTTPable pages with no data (AJAX or 302)
   autohandler -- turns off header/footer
   delete-post -- deletes the given post id
   edit-post -- updates (currently just creates) a post
 comp/ -- non-HTTPable HTML snippets
   post -- a complete form or display post
   field -- a field for such a post
 func/ -- non-HTTPable Mason code
   setup -- shared setup code for all pages in the app
 includes/ -- browser includes (JS & CSS)
   masonblog.css -- stylesheet for app
   masonblog.js -- custom js for app
   prototype.js -- Prototype library
   scriptaculous/ -- Scriptaculous libraries
 autohandler -- func/setup + header/footer
 index.html -- index page (currently only "real" page!)
 
HTML Subsection Components
MasonBlog™ will have two non-request HTML components:
 - HTML snippet for an individual post
- HTML snippet for an individual field of a post
 
Field HTML Component
[comp/field]
 - Creates a text input or displays the text; starting point for more general
  set of HTML generation components
 
Post HTML Component
[comp/post]
 - "Create Form" and "View" will share same component
- Not necessarily (or even often) the best approach
- Balance of reuse vs. spaghetti code
- Uses supplied parameters for efficiency if available
 
Action Components
 - delete-post:
   Accepts a post id, and deletes it (no authentication!)
- edit-post:
   Creates or edits a post entry given author and content.
   In AJAX mode, sends back the HTML of the new post entry from
   the post component
 
Alternative Approach
 - A Mason component with a <%args> section (like post) can be 
  transparently accessed using <& ... &> tags or
  via a direct HTTP request
- This means that the component that you used as part of a larger page to
  render the HTML could be called directly via XMLHTTPRequest to
  render a snippet of HTML for presentation.
- In practice, not all that useful
 
Overview
 - Know Your Tools
- Don't Repeat Yourself
- Survive JavaScriptlessness
- Get Organized
- Be Secure
 
Be Secure
 - Much like private, public, and protected in 
  your favorite B&D language, your web app should have correct permissions
- autohandler and dhandler should not be web-fetchable
- The contents of CVS/ and .svn/ directories should not
  be web-fetchable
- Mason components (HTML or code) that are only called from other Mason 
  components should not be web-fetchable (in our case, func/ 
  and comp/)
 
Overview
 - Know Your Tools
- Don't Repeat Yourself
- Survive JavaScriptlessness
- Get Organized
- Be Secure
- Don't Repeat Yourself