[Jifty-commit] r2205 - in jifty/branches/template-declare: . lib/Jifty

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Mon Nov 27 18:49:08 EST 2006


Author: jesse
Date: Mon Nov 27 18:49:08 2006
New Revision: 2205

Added:
   jifty/branches/template-declare/lib/Jifty/View/Declare/BaseView.pm
Modified:
   jifty/branches/template-declare/   (props changed)
   jifty/branches/template-declare/lib/Jifty/ClassLoader.pm
   jifty/branches/template-declare/lib/Jifty/View/Declare/Handler.pm
   jifty/branches/template-declare/lib/Jifty/View/Declare/Templates.pm

Log:
 r45510 at pinglin:  jesse | 2006-11-27 18:48:44 -0500
 * more work on the declarative views. (Including a first stab at porting the mason templates to T::D.
   Help me audrey-tan! (San check at least)


Modified: jifty/branches/template-declare/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/ClassLoader.pm	Mon Nov 27 18:49:08 2006
@@ -130,6 +130,11 @@
                   "use warnings; use strict; package $module;\n"
                 . "use base qw/Jifty::$1/; sub _autogenerated { 1 };\n"
                 . "1;" );
+    } elsif ( $module =~ m!^(?:$base)::View$! ) {
+        return $self->return_class(
+                  "use warnings; use strict; package $module;\n"
+                . "use base qw/Jifty::View::Declare::Templates/; sub _autogenerated { 1 };\n"
+                . "1;" );
     } elsif ( $module =~ m!^(?:$base)::CurrentUser$! ) {
         return $self->return_class(
                   "use warnings; use strict; package $module;\n"

Added: jifty/branches/template-declare/lib/Jifty/View/Declare/BaseView.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/View/Declare/BaseView.pm	Mon Nov 27 18:49:08 2006
@@ -0,0 +1,1381 @@
+die "This needs a better name, also to compile and not suck. (This is an unfinished port of our mason templates to Template::Declare";
+__DATA__
+sub __jifty::subs { 
+    my ($forever) = get(qw(forever)) || 1;
+    
+$r->content_type("text/html; charset=utf-8");
+$r->headers_out->{'Pragma'} = 'no-cache';
+$r->headers_out->{'Cache-control'} = 'no-cache';
+$r->send_http_header;
+
+my $writer = XML::Writer->new;
+$writer->xmlDecl( "UTF-8", "yes" );
+
+my $begin = <<'END';
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-strict.dtd">
+<html><head><title></title></head>
+END
+chomp $begin;
+
+
+if ($forever) {
+    my $whitespace = " " x ( 1024 - length $begin );
+    $begin =~ s/<body>$/$whitespacebody/s;
+}
+
+$m->print($begin);
+$m->flush_buffer;
+$writer->startTag("body");
+
+
+    while (1) {
+        my $sent = write_subs_once($writer);
+        flush STDOUT;
+        last if ($sent && !$forever);
+        sleep 1;
+    }
+    $writer->endTag();
+    return;
+
+
+
+}
+
+sub write_subs_once {
+    my $writer = shift;
+    Jifty::Subs::Render->render(
+        Jifty->web->session->id,
+        sub {
+            my ( $mode, $name, $content ) = @_;
+            $writer->startTag( "pushfrag", mode => $mode );
+            $writer->startTag( "fragment", id   => $name );
+            $writer->dataElement( "content", $content );
+            $writer->endTag();
+            $writer->endTag();
+        }
+    );
+}
+
+sub __jifty::admin::_elements::nav {
+
+    my $nav = Jifty->web->navigation->child(
+        "Administration" => url => '/__jifty/admin/' );
+    foreach my $model ( Jifty->class_loader->models ) {
+        next unless $model->isa('Jifty::Record');
+        next unless ( $model =~ /^(?:.*)::(.*?)$/ );
+        my $type = $1;
+        $nav->child( $type => url => '/__jifty/admin/model/' . $type );
+    }
+    return;
+}
+
+sub __jifty::admin::action::dhandler {
+    my $action_class = Jifty->api->qualify( $m->dhandler_arg );
+
+    my $action = new_action(
+        class   => $action_class,
+        moniker => "run-$action_class",
+    );
+
+    $action->sticky_on_failure(1);
+    wrapper {
+
+        form {
+
+            for ( $action->argument_names ) {
+                param( $action, $_ );
+            }
+
+            submit( label => _("Run the action") );
+            }
+
+            h2 { _('Done?') };
+        hyperlink(
+            url   => "/__jifty/admin/",
+            label => _('Back to the admin console')
+        );
+
+        }
+}
+
+sub __jifty::admin::autohandler { 
+
+# If "AdminMode" is turned off in Jifty's config file, don't let people at the admin UI.
+unless (Jifty->config->framework('AdminMode')) {
+    redirect('/__jifty/error/permission_denied'); 
+    return;
+}
+show ('admin::elements::nav'); # XXX TODO hm. should be in dispatcher.
+}
+
+sub __jifty::admin::fragments::list::list { 
+my ( $object_type $page $new_slot $item_path ) = get(qw( object_type page new_slot item_path ));
+
+$page ||= 1;
+$new_slot  = 1 unless defined $new_slot;
+$item_path ||= "/__jifty/admin/fragments/list/view"
+
+my $collection_class = Jifty->app_class("Model", $object_type."Collection");
+my $search = Jifty->web->response->result('search');
+my $collection;
+if(!$search) {
+    $collection = $collection_class->new();
+    $collection->unlimit();
+} else {
+    $collection = $search->content('search');
+    warn $collection->build_select_query;
+}
+
+$collection->set_page_info( current_page => $page,
+                            per_page     => 25
+                           );
+my $search_region = Jifty::Web::PageRegion->new(
+   name     => 'search',
+   path     => '/__jifty/empty',
+);
+
+ hyperlink(
+    onclick => [{
+        region       => $search_region->qualified_name,
+        replace_with => '/__jifty/admin/fragments/list/search',
+        toggle       => 1,
+        args         => { object_type => $object_type }
+    },
+    ],
+    label => 'Toggle search'
+  );
+
+ $search_region->render ;
+
+ if ($collection->pager->last_page > 1) {
+    with ( class => "page-count"), span { _('Page [_1] of [_2]', $page ,  $collection->pager->last_page)}   
+ }
+
+ if ($collection->pager->total_entries == 0) {
+  _('No items found')
+ }
+
+with ( class => "list"), div {
+while ( my $item = $collection->next ) {
+    Jifty->web->region(
+        name     => 'item-' . $item->id,
+        path     => $item_path,
+        defaults => { id => $item->id, object_type => $object_type }
+    );
+}
+
+}
+
+with ( class => "paging"), div {
+ if ($collection->pager->previous_page) {
+with ( class => "prev-page"), span {
+   hyperlink( label => "Previous Page", onclick => { args => { page => $collection->pager->previous_page } } );
+}
+ }
+ if ($collection->pager->next_page) {
+with ( class => "next-page"), span {
+   hyperlink( label => "Next Page", onclick => { args => { page => $collection->pager->next_page } } )
+}
+ }
+}
+
+ if ($new_slot) {
+ Jifty->web->region(
+        name => 'new_item',
+        path => "/__jifty/admin/fragments/list/new_item",
+        defaults => {   object_type => $object_type },
+        ) 
+
+}
+
+
+}
+
+# When you hit "save" and create a item, you want to put a fragment
+# containing the new item in the associated list and refresh the current
+# fragment
+# 
+sub __jifty::admin::fragments::list::new_item { 
+my ( $object_type, $region) = get(qw(object_type region));
+my $record_class = Jifty->app_class("Model", $object_type);
+ my $create = new_action(class => 'Create'.$object_type);
+with ( class => "jifty_admin create item inline"), div {
+ foreach my $argument ($create->argument_names) {
+        param ($create=>$argument);
+}
+}
+
+Jifty->web->form->submit(
+    label    => 'Create',
+    onclick  => [
+                 { submit => $create },
+                 { refresh_self => 1 },
+                 {
+                   element => $region->parent->get_element('div.list'),
+                   append => '/__jifty/admin/fragments/list/view',
+                   args   => { 
+                              object_type => $object_type,
+                              id          => { result_of => $create, name => 'id' },
+                             },
+                 },
+                ]
+    ) 
+
+}
+
+sub __jifty::admin::fragments::list::search { 
+my (
+$object_type
+) = get(qw(object_type));
+my $search = new_action(
+    class             => "Search".$object_type,
+    moniker           => "search",
+    sticky_on_success => 1,
+);
+
+with ( class => "jifty_admin"), div {
+ for my $arg ($search->argument_names) {
+    param($search => $arg);
+ }
+
+ $search->button(
+    label   => 'Search!',
+    onclick => {
+        submit  => $search,
+        refresh => Jifty->web->current_region->parent,
+        args    => { page => 1}
+    }
+  )
+hr {};
+}
+}
+
+sub __jifty::admin::fragments::list::update { 
+my ( $id $object_type) = get(qw(id object_type));
+my $record_class = Jifty->app_class("Model", $object_type);
+my $record = $record_class->new();
+my $update = new_action(
+    class   => "Update".$object_type,
+    moniker => "update-" . Jifty->web->serial,
+    record  => $record
+);
+with ( class => "jifty_admin update item inline $object_type">, div {
+with ( class => "editlink"), div {
+   hyperlink(
+      label   => _("Save"),
+      onclick => [
+          { submit => $update },
+          {   replace_with => '/__jifty/admin/fragments/list/view',
+              args         => { object_type => $object_type, id => $id }
+          }
+      ]
+      ) 
+
+   hyperlink(
+      label     => _("Cancel"),
+      onclick   => {
+          replace_with => '/__jifty/admin/fragments/list/view',
+          args         => { object_type => $object_type, id => $id }
+        },
+      as_button => 1
+  )
+
+};
+
+ foreach my $argument ($update->argument_names) {
+    param($update=>$argument);
+}
+hr {};
+}
+
+}
+
+sub __jifty::admin::fragments::list::view { 
+my (
+$id => undef
+$object_type
+) = get(qw());
+my $record_class = Jifty->app_class("Model", $object_type);
+my $record = $record_class->new();
+$record->load($id);
+my $update = new_action(
+    class   => "Update".$object_type,
+    moniker => "update-" . Jifty->web->serial,
+    record  => $record
+);
+my $delete = new_action(
+    class   => "Delete".$object_type,
+    moniker => "delete-" . Jifty->web->serial,
+    record  => $record
+);
+
+with ( class => "jifty_admin read item inline"), div {
+  
+    Jifty->web->form->submit(
+        class   => "editlink",
+        label   => "Delete",
+        submit => $delete,
+        onclick => { 
+         confirm => _("Confirm delete?"), 
+         delete =>  Jifty->web->current_region->qualified_name
+        },
+        );
+    hyperlink(
+        label   => "Edit",
+        class   => "editlink",
+        onclick => {
+            replace_with => "/__jifty/admin/fragments/list/update",
+            args         => { object_type => $object_type, id => $id }
+            },
+        as_button => 1
+        );
+
+ $delete->hidden('id',$id) ;
+ foreach my $argument ($update->argument_names) {
+ unless(   $argument =~ /_confirm$/
+        && lc $update->arguments->{$argument}{render_as} eq 'password') {
+  param($update => $argument, render_mode => 'read');
+ }
+ };
+
+hr {};
+}
+
+}
+
+sub __jifty::admin::index {
+    with( title => 'Jifty Administrative Console' ), wrapper {
+
+        h1 { _('Database Administration') };
+
+        p {
+            _(  'This console lets you manage the records in your Jifty database. Below, you should see a list of all your database tables. Feel free to go through and add, delete or modify records.'
+            );
+        };
+
+        p {
+            _(  q{To disable this administrative console, add "framework: AdminMode: 0" to your application's configuration file.}
+            );
+        };
+
+        h2 { _('Models') };
+        ul {
+            foreach my $model ( Jifty->class_loader->models ) {
+                next unless $model->isa('Jifty::Record');
+                next unless ( $model =~ /^(?:.*)::(.*?)$/ );
+                my $type = $1;
+                li {
+                    hyperlink(
+                        url   => '/__jifty/admin/model/' . $type,
+                        label => $type
+                    );
+                    }
+            }
+            }
+            h2 { _('Actions') } ul {
+            foreach my $action ( Jifty->api->actions ) {
+                Jifty::Util->require($action);
+                next
+                    if ($action->can('autogenerated')
+                    and $action->autogenerated );
+                li {
+                    hyperlink(
+                        url   => '/__jifty/admin/action/' . $action,
+                        label => $action
+                    );
+                    }
+            }
+            }
+            h2 { _('Done?') } Jifty->web->return(
+            to    => "/",
+            label => 'Back to the application'
+            );
+        }
+}
+
+sub __jifty::admin::model::dhandler { 
+my $object_type = $m->dhandler_arg;
+
+my $collection_class =  Jifty->app_class("Model", $object_type."Collection");
+my $records = $collection_class->new();
+$records->unlimit;
+wrapper {
+h1 {_('Manage records: [_1]',$object_type) };
+form {
+ Jifty->web->region(name => "admin-$object_type",
+                      path => "/__jifty/admin/fragments/list/list", 
+                      defaults => { object_type => $object_type , 
+                                    render_submit => 1 });
+
+                                };
+
+h2 {_('Done?')}
+ hyperlink( url => "/__jifty/admin/", label => 'Back to the admin console');
+
+}
+}
+
+sub __jifty::autocomplete.xml { 
+# Note: the only point to this file is to set the content_type; the actual
+# behavior is accomplished inside the framework.  It will go away once we
+# have infrastructure for serving things of various content-types.
+$r->content_type('text/xml; charset=UTF-8');
+my $ref =  Jifty->web->response->result('autocomplete')->content;
+my @options = @{$ref->{'completions'}||[]};
+body {
+ul { 
+% foreach my $item ( @options) {
+%    if (!ref($item)) {
+li {<% $item %>}
+%    } elsif (exists $item->{label}) {
+li {with ( class => "informal"), span {<% $item->{label} %>}with ( class => "hidden_value"), span {<% $item->{value} %>}}
+%    } else {
+li {<% $item->{value} %>}
+%    }
+%}
+}
+</body>
+}
+
+sub __jifty::css::dhandler { 
+if ( $m->dhandler_arg !~ /^[0-9a-f]{32}\.css$/ ) {
+    # This doesn't look like a real request for squished CSS,
+    # so redirect to a more failsafe place
+    Jifty->web->redirect( "/static/css/" . $m->dhandler_arg );
+}
+
+Jifty->web->generate_css;
+
+use HTTP::Date ();
+
+if ( Jifty->handler->cgi->http('If-Modified-Since')
+        and $m->dhandler_arg eq Jifty->web->cached_css_digest . '.css' )
+{
+    Jifty->log->debug("Returning 304 for cached css");
+    $r->header_out( Status => 304 );
+    return;
+}
+
+$r->content_type("text/css");
+$r->header_out( 'Expires' => HTTP::Date::time2str(time + 31536000) );
+
+# XXX TODO: If we start caching the squished CSS in a file somewhere, we
+# can have the static handler serve it, which would take care of gzipping
+# for us.
+use Compress::Zlib qw();
+
+if ( Jifty::View::Static::Handler->client_accepts_gzipped_content ) {
+    Jifty->log->debug("Sending gzipped squished CSS");
+    $r->header_out( "Content-Encoding" => "gzip" );
+    binmode STDOUT;
+    print Compress::Zlib::memGzip( Jifty->web->cached_css );
+}
+else {
+    Jifty->log->debug("Sending squished CSS");
+    print Jifty->web->cached_css;
+}
+return;
+}
+
+sub __jifty::empty { 
+}
+
+sub __jifty::error::_elements::error_text { 
+h1 {Sorry, something went awry}
+p { For one reason or another, you got to a web page that caused a bit
+of an error. And then you got to our "basic" error handler. Which
+means we haven't written a pretty, easy to understand error message
+for you just yet. The message we <em>do</em> have is:}
+
+<blockquote>
+<b><% $error %></b>
+</blockquote>
+
+p { There's a pretty good chance that error message doesn't mean
+anything to you, but we'd rather you have a little bit of information
+about what went wrong than nothing. We've logged this error, so we
+know we need to write something friendly explaining just what happened
+and how to fix it.}
+
+p { For now <% hyperlink( url =>"/", label => 'head on back
+home')%> and try to forget that we let you down.}
+my (
+$error
+) = get(qw());}
+
+sub __jifty::error::_elements::wrapper { 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+  <title>Mason error</title>  
+  <link rel="stylesheet" type="text/css" href="/__jifty/error/error.css" media="all" />
+</head>
+body {
+  with ( id => "headers"), div {
+    <h1 class="title">Mason error}
+  }
+  with ( id => "content"), div {
+    <a name="content"></a>
+% if (Jifty->config->framework('AdminMode') ) {
+with ( class => "warning admin_mode"), div {
+Alert: Jifty <% Jifty->web->tangent( label => 'administration mode' , url => '/__jifty/admin/')%> is enabled.
+}
+% }
+  <% Jifty->web->render_messages %>
+
+  <% $m->content |n%>
+
+  }
+</body>
+</html>
+<%doc>
+
+This exists as a fallback wrapper, in case the mason error in question
+is caused by the Jifty app's wrapper, for instance.
+
+</%doc>}
+
+sub __jifty::error::autohandler { 
+<%flags>
+inherit => undef
+</%flags>
+% $m->call_next}
+
+sub __jifty::error::dhandler { 
+Jifty->log->error("Unhandled web error ". $m->dhandler_arg);
+<&|/_elements/wrapper, title => 'Something went awry' &>
+
+<& _elements/error_text, error => $m->dhandler_arg &>
+
+</&>
+}
+
+sub __jifty::error::error.css { 
+$r->content_type("text/css");
+h1 {
+    color: red;
+}
+
+}
+sub __jifty::error::mason_internal_error { 
+my $wrapper = "/_elements/wrapper";
+
+my $cont = Jifty->web->request->continuation;
+$wrapper = "/__jifty/error/_elements/wrapper"
+  if $cont
+  and $cont->request->path eq "/__jifty/error/mason_internal_error";
+
+# If we're not in devel, bail
+if ( not Jifty->config->framework("DevelMode") or not $cont ) {
+  $m->comp(
+    $wrapper,
+      content => sub {
+        $m->comp( "_elements/error_text", error => "mason internal error" );
+      },
+      title => "Something went awry"
+  );
+  $m->abort;
+}
+
+my $e   = $cont->response->error;
+my $msg = $e->message;
+$msg =~ s/, <\S+> (line|chunk) \d+\././;
+
+my $info  = $e->analyze_error;
+my $file  = $info->{file};
+my @lines = @{ $info->{lines} };
+my @stack = @{ $info->{frames} };
+<&| $wrapper, title => "Mason error" &>
+
+Error in <& .line, file => $file, line => "@lines" &>
+<pre><% $msg %></pre>
+
+<% Jifty->web->return( label => "Try again" ) %>
+
+h2 {Call stack};
+ul { 
+% for my $frame (@stack) {
+%   next if $frame->filename =~ m{/HTML/Mason/};
+    li {<& .line, file => $frame->filename, line => $frame->line &>}
+% }
+}
+ 
+</&>
+
+<%def .line>
+my (
+$file
+$line
+) = get(qw());
+%   if (-w $file) {
+%     my $path = $file;
+%     for (map {$_->[1]} @{Jifty->handler->mason->interp->comp_root}) {
+%       last if $path =~ s/^\Q$_\E//;
+%     }
+%     if ($path ne $file) {
+template <% Jifty->web->tangent( url =>"/__jifty/edit/mason_component$path",
+                                 label => "$path line ".$line,
+                                 parameters => { line => $line } ) %>
+%     } else {
+<% Jifty->web->tangent( url =>"/__jifty/edit/library$path",
+                        label => "$path line ".$line,
+                        parameters => { line => $line } ) %>
+%     }
+%   } else {
+<% $file %> line <% $line %>
+%   }
+</%def>
+
+}
+
+sub __jifty::halo { 
+for my $id (0..$#stack) {
+    my @kids;
+    my $looking = $id;
+    while (++$looking <= $#stack and $stack[$looking]->{depth} >= $stack[$id]->{depth} + 1) {
+        push @kids, {id => $stack[$looking]{id}, path => $stack[$looking]{path}, render_time => $stack[$looking]{render_time}}
+          if $stack[$looking]->{depth} == $stack[$id]->{depth} + 1;
+    }
+    $stack[$id]{kids} = \@kids;
+
+    if ($stack[$id]{depth} > 1) {
+        $looking = $id;
+        $looking-- while ($stack[$looking]{depth} >= $stack[$id]{depth});
+        $stack[$id]{parent} = {id => $stack[$looking]{id}, path => $stack[$looking]{path}, render_time => $stack[$looking]{render_time}};
+    }
+}
+
+my $depth = 0;
+
+ div {outs('<a href="#" id="render_info" onclick="Element.toggle('render_info_tree'); return false">Page info</a>')};
+with( style=>"display: none" , id=> "render_info_tree"), div { 
+ foreach my $item (@stack) {
+     if ( $item->{depth} > $depth ) {
+ul { 
+     } elsif ( $item->{depth} < $depth ) {
+         for ($item->{depth}+1 .. $depth) {
+}}
+         }
+}
+     } elsif ( $item->{depth} == $depth ) {
+}
+     }
+
+li {
+    outs('<a href="#" class="halo_comp_info" 
+    onmouseover="halo_over('<% $item->{id} %>')"
+    onmouseout="halo_out('<% $item->{id} %>')"
+    onclick="halo_toggle('<% $item->{id} %>'); return false;">
+<% $item->{'name'} %> - <% $item->{'render_time'} %></a>');
+ unless ($item->{subcomponent}) {
+Jifty->web->tangent( url =>"/__jifty/edit/mason_component/".$item->{'path'}, label => 'Edit') ;
+ }
+ $depth = $item->{'depth'};
+ }
+
+ for (1 .. $depth) {
+}}
+ }
+}
+
+% foreach my $item (@stack) {
+<& .frame, frame => $item &>
+% }
+my ( @stack) = get(qw(stack));
+
+
+
+<%def .frame>
+with ( class => "halo_actions" id="halo-<% $id %), div {-menu" style="display: none; top: 5px; left: 500px; min-width: 200px; width: 300px; z-index: 5;">
+<h1 id="halo-<% $id %>-title">
+  <span style="float: right;"><a href="#" onclick="halo_toggle('<% $id %>'); return false">[ X ]</a>}
+  <% $frame->{name} %>
+}
+<div style="position: absolute; bottom: 3px; right: 3px">with ( class => "resize" title="Resize" id="halo-<% $id %), span {-resize">}}
+
+with ( class => "body"), div {
+with ( class => "path"), div {<% $frame->{path} %>}
+with ( class => "time"), div {Rendered in <% $frame->{'render_time'} %>s}
+}
+% if ($frame->{parent}) {
+with ( class => "section"), div {Parent}
+with ( class => "body"), div {ul { 
+li {<a href="#" class="halo_comp_info" onmouseover="halo_over('<% $frame->{parent}{id} %>')"
+                                       onmouseout="halo_out('<% $frame->{parent}{id} %>')"
+                                       onclick="halo_toggle('<% $frame->{parent}{id} %>'); return false;">
+<% $frame->{parent}{'path'} %> - <% $frame->{parent}{'render_time'} %></a>}
+}}
+% }
+% if (@{$frame->{kids}}) {
+with ( class => "section"), div {Children}
+with ( class => "body"), div {ul { 
+% for my $item (@{$frame->{kids}}) {
+li {<a href="#" class="halo_comp_info" onmouseover="halo_over('<% $item->{id} %>')"
+                                       onmouseout="halo_out('<% $item->{id} %>')"
+                                       onclick="halo_toggle('<% $item->{id} %>'); return false;">
+<% $item->{'path'} %> - <% $item->{'render_time'} %></a>}
+% }
+}
+}
+% }
+% if (@args) {
+with ( class => "section"), div {Variables}
+with ( class => "body"), div {<ul class="fixed">
+% for my $e (@args) {
+li {<b><% $e->[0] %></b>:
+% if ($e->[1]) {
+% my $expanded = Jifty->web->serial;
+<a href="#" onclick="Element.toggle('<% $expanded %>'); return false"><% $e->[1] %></a>
+with ( id => "<% $expanded %), div {" style="display: none; position: absolute; left: 200px; border: 1px solid black; background: #ccc; padding: 1em; padding-top: 0; width: 300px; height: 500px; overflow: auto"><pre><% Jifty::YAML::Dump($e->[2]) %></pre>}
+% } elsif (defined $e->[2]) {
+<% $e->[2] %>
+% } else {
+<i>undef</i>
+% }
+}
+% }
+}}
+% }
+% if (@stmts) {
+with ( class => "section"), div {<%_('SQL Statements')%>}
+with ( class => "body" style="height: 300px; overflow: auto"), div {ul { 
+% for (@stmts) {
+li {
+with ( class => "fixed"), span {<% $_->[1] %>}<br />
+% if (@{$_->[2]}) {
+<b>Bindings:</b> <tt><% join(',', map {defined $_ ? ($_ =~ /[^[:space:][:graph:]]/ ? "*BLOB*" : $_ ) : "undef"} @{$_->[2]}) %></tt><br />
+% }
+<i><% _('%1 seconds', $_->[3]) %></i>
+}
+ }
+}}
+ }
+with ( class => "section"), div {
+ unless ($frame->{subcomponent}) {
+Jifty->web->tangent( url =>"/__jifty/edit/mason_component/".$frame->{'path'}, label => 'Edit');
+ } else {
+outs('&nbsp;');
+% }
+}
+}
+my ( $frame) = get(qw(frame));
+my $id = $frame->{id};
+
+my @args;
+while (my ($key, $value) = splice(@{$frame->{args}},0,2)) {
+    push @args, [$key, ref($value), $value];
+}
+ at args = sort {$a->[0] cmp $b->[0]} @args;
+
+my $prev = '';
+my @stmts = @{$frame->{'sql_statements'}};
+</%def>
+}
+
+sub __jifty::js::dhandler {
+    if ( $m->dhandler_arg !~ /^[0-9a-f]{32}\.js$/ ) {
+
+        # This doesn't look like a real request for squished JS,
+        # so redirect to a more failsafe place
+        Jifty->web->redirect( "/static/js/" . $m->dhandler_arg );
+    }
+
+    Jifty->web->generate_javascript;
+
+    use HTTP::Date ();
+
+    if ( Jifty->handler->cgi->http('If-Modified-Since')
+        and $m->dhandler_arg eq Jifty->web->cached_javascript_digest . '.js' )
+    {
+        Jifty->log->debug("Returning 304 for cached javascript");
+        $r->header_out( Status => 304 );
+        return;
+    }
+
+    $r->content_type("application/x-javascript");
+    $r->header_out( 'Expires' => HTTP::Date::time2str( time + 31536000 ) );
+
+    # XXX TODO: If we start caching the squished JS in a file somewhere, we
+    # can have the static handler serve it, which would take care of gzipping
+    # for us.
+    use Compress::Zlib qw();
+
+    if ( Jifty::View::Static::Handler->client_accepts_gzipped_content ) {
+        Jifty->log->debug("Sending gzipped squished JS");
+        $r->header_out( "Content-Encoding" => "gzip" );
+        binmode STDOUT;
+        print Compress::Zlib::memGzip( Jifty->web->cached_javascript );
+    } else {
+        Jifty->log->debug("Sending squished JS");
+        print Jifty->web->cached_javascript;
+    }
+    return;
+}
+
+sub __jifty::online_docs::autohandler {
+
+# If "AdminMode" is turned off in Jifty's config file, don't let people at the admin UI.
+    unless ( Jifty->config->framework('AdminMode') ) {
+        $m->redirect('/__jifty/error/permission_denied');
+        $m->abort();
+    }
+
+    $m->call_next();
+}
+
+sub __jifty::online_docs::content.html { 
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
+<head>
+<title><% _( $n || 'Jifty') %> - <%_('Jifty Pod Online')%></title>
+<style type="text/css"><!--
+a { text-decoration: none }
+a:hover { text-decoration: underline }
+a:focus { background: #99ff99; border: 1px black dotted }
+--></style>
+</head>
+body {
+<%PERL>
+my $jifty_dirname = Jifty::Util->jifty_root."/";
+my $app_dirname = Jifty::Util->app_root."/lib/";
+$n =~ s/::/\//g;
+
+my @options = (
+    $app_dirname.$n.".pod",
+    $app_dirname.$n.".pm",
+    $jifty_dirname.$n.".pod",
+    $jifty_dirname.$n.".pm");
+
+my $total_body;
+foreach my $file (@options) {
+    next unless -r "$file";
+    local $/;
+    my $fh;
+    open $fh, "$file" or next;
+    $total_body = <$fh>;
+    close $fh;
+}
+my $body;
+my $schema;
+my $converter = Pod::Simple::HTML->new();
+if($n !~ /^Jifty\//) {
+    if ($total_body =~ /package (.*?)::Schema;(.*)package/ismx) {
+         $schema = $2;
+    }
+}
+
+
+$converter->output_string( \$body );
+$converter->parse_string_document($total_body);
+$body =~ s{.*?<body [^>]+>}{}s;
+$body =~ s{</body>\s*</html>\s*$}{};
+$n    =~ s{/}{::}g;
+$m->print("h1 {$n}");
+$m->print("h2 {"._('Schema')."}<pre>$schema</pre>") if ($schema);
+$body =~ s{<a href="http://search\.cpan\.org/perldoc\?(Jifty%3A%3A[^"]+)"([^>]*)>}{<a href="content.html?n=$1"$2>}g;
+$body =~ s!}\n\tul { !ul { !;
+$body =~ s!}!}}!;
+$body =~ s!p { }!!;
+$body =~ s!<a name=!<a id=!g;
+$body =~ s!__index__!index!g;
+$m->print($body);
+</%PERL>
+</body></html>
+<%ARGS>
+$Target    => '&method=content'
+$n  => 'Jifty'
+</%ARGS>
+require File::Basename;
+require File::Find;
+require File::Temp;
+require File::Spec;
+require Pod::Simple::HTML;
+}
+
+sub __jifty::online_docs::index.html { 
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
+"http://www.w3.org/TR/html4/">
+<html lang="en">
+<head>
+<title><%_( $n || 'Jifty') %> - <%_('Online Documentation')%></title>
+<style type="text/css"><!--
+a { text-decoration: none }
+a:hover { text-decoration: underline }
+a:focus { background: #99ff99; border: 1px black dotted }
+--></style>
+</head>
+<FRAMESET COLS="*, 250">
+    <FRAME src="./content.html" name="podcontent">
+    <FRAME src="./toc.html" name="podtoc">
+    <NOFRAMES>
+        <a style="display: none" href="#toc"><%_('Table of Contents')%></a>
+<& content.html, Target => '' &>
+        h1 {<a id="toc"><%_('Table of Contents')%></a>}
+<& toc.html, Target => '' &>
+    </NOFRAMES>
+</FRAMESET>
+my (
+$n => undef
+) = get(qw());
+}
+
+sub __jifty::online_docs::toc.html { 
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
+<head>
+<title><% _($n || 'Jifty') %> - <%_('Jifty Developer Documentation Online')%></title>
+<style type="text/css"><!--
+a { text-decoration: none }
+a:hover { text-decoration: underline }
+a:focus { background: #99ff99; border: 1px black dotted }
+--></style>
+</head>
+<body style="background: #dddddd">
+<%PERL>
+my @found;
+File::Find::find(
+    { untaint => 1,
+      wanted => sub {
+        return unless /(\w+)\.(?:pm|pod)$/;
+        my $name = $File::Find::name;
+        $name =~ s/.*lib\b.//;
+        $name =~ s!\.(?:pm|pod)!!i;
+        $name =~ s!\W!::!g;
+        push @found, $name;
+    },follow => ($^O ne 'MSWin32') },
+    Jifty::Util->app_root ."/lib",
+);
+
+
+File::Find::find(
+    { untaint => 1,
+      wanted => sub {
+        return unless $File::Find::name =~ /^(?:.*?)(Jifty.*?\.(?:pm|pod))$/;
+        my $name = $1;
+        $name =~ s/.*lib\b.//;
+        $name =~ s!\.(?:pm|pod)!!i;
+        $name =~ s!\/!::!g;
+        push @found, $name;
+    },follow => ($^O ne 'MSWin32') },
+    Jifty::Util->jifty_root,
+);
+
+my $indent = 0;
+my $prev = '';
+foreach my $file (sort @found) {
+    my ($parent, $name) = ($1, $2) if $file =~ /(?:(.*)::)?(\w+)$/;
+    $parent = '' unless defined $parent;
+    if ($file =~ /^$prev\::(.*)/) {
+        my $foo = $1;
+        while ($foo =~ s/(\w+):://) {
+            $indent++;
+            $m->print(('&nbsp;&nbsp;&nbsp;' x $indent));
+            $m->print("$1<br />");
+        }
+        $indent++;
+    } elsif ($prev !~ /^$parent\::/) {
+        $indent = 0 unless length $parent;
+        while ($parent =~ s/(\w+)//) {
+            next if $prev =~ s/\b$1:://;
+            while ($prev =~ s/:://) {
+                $indent--;
+            }
+            $m->print(('&nbsp;&nbsp;&nbsp;' x $indent));
+            $m->print("$1<br />");
+            $indent++;
+        }
+    } elsif ($prev =~ /^$parent\::(.*::)/) {
+        my $foo = $1;
+        while ($foo =~ s/:://) {
+            $indent--;
+        }
+    }
+    $m->print( ( '&nbsp;&nbsp;&nbsp;' x $indent )
+      . '<a target="podcontent" href="content.html?n=' . $file . '">' . $name
+      . '</a><br />' ."\n" );
+    $prev = $file;
+}
+
+</%PERL>
+</body></html>
+<%INIT>
+require File::Basename;
+require File::Find;
+require File::Temp;
+require File::Spec;
+require Pod::Simple::HTML;
+</%INIT>
+<%ARGS>
+$n  => ''
+$method => ''
+$Target    => '&method=content'
+</%ARGS>
+}
+
+sub __jifty::validator.xml { 
+$r->content_type('text/xml; charset=UTF-8');
+
+my $output = "";
+use XML::Writer;
+my $writer = XML::Writer->new( OUTPUT => \$output );
+$writer->xmlDecl( "UTF-8", "yes" );
+$writer->startTag("validation");
+for my $ra ( Jifty->web->request->actions ) {
+    my $action = Jifty->web->new_action_from_request($ra);
+    $writer->startTag( "validationaction", id => $action->register_name );
+    for my $arg ( $action->argument_names ) {
+        if ( not $action->arguments->{$arg}->{ajax_validates} ) {
+            $writer->emptyTag( "ignored", id => $action->error_div_id($arg) );
+            $writer->emptyTag( "ignored", id => $action->warning_div_id($arg) );
+        } elsif ( not $action->arguments->{$arg}->{mandatory}
+		  and (not defined $action->argument_value($arg)
+                       or length $action->argument_value($arg) == 0 ) ) {
+            $writer->emptyTag( "blank", id => $action->error_div_id($arg) );
+            $writer->emptyTag( "blank", id => $action->warning_div_id($arg) );
+        } elsif ( $action->result->field_error($arg) ) {
+            $writer->dataElement(
+                "error",
+                $action->result->field_error($arg),
+                id => $action->error_div_id($arg)
+            );
+            $writer->emptyTag( "ok", id => $action->warning_div_id($arg) );
+        } elsif ( $action->result->field_warning($arg) ) {
+            $writer->dataElement(
+                "warning",
+                $action->result->field_warning($arg),
+                id => $action->warning_div_id($arg)
+            );
+            $writer->emptyTag( "ok", id => $action->error_div_id($arg) );
+        } else {
+            $writer->emptyTag( "ok", id => $action->error_div_id($arg) );
+            $writer->emptyTag( "ok", id => $action->warning_div_id($arg) );
+        }
+    }
+    $writer->endTag();
+    $writer->startTag( "canonicalizeaction", id => $action->register_name );
+    for my $arg ( $action->argument_names ) {
+        if ($ra->arguments->{$arg} eq $action->argument_value($arg) ) {
+            # if the value doesn't change, it can be ignored.
+            # canonicalizers can change other parts of the action, so we want to send all changes
+            $writer->emptyTag( "ignored", name => $action->form_field_name($arg) );
+        } elsif ( not defined $action->argument_value($arg)
+            or length $action->argument_value($arg) == 0 ) {
+            $writer->emptyTag( "blank", name => $action->form_field_name($arg) );
+        } else {
+            if ( $action->result->field_canonicalization_note($arg) ) {
+                $writer->dataElement(
+                    "canonicalization_note",
+                    $action->result->field_canonicalization_note($arg),
+                    id => $action->canonicalization_note_div_id($arg)
+                );
+            }
+            $writer->dataElement(
+                "update",
+                $action->argument_value($arg),
+                name => $action->form_field_name($arg)
+            );
+        }
+    }
+    $writer->endTag();
+}
+$writer->endTag();
+$m->out($output);
+$m->abort();
+}
+
+sub __jifty::webservices::xml { 
+my $output = "";
+my $writer = XML::Writer->new( OUTPUT => \$output, UNSAFE => 1 );
+$writer->xmlDecl( "UTF-8", "yes" );
+$writer->startTag("response");
+for my $f ( Jifty->web->request->fragments ) {
+    # Set up the region stack
+    local Jifty->web->{'region_stack'} = [];
+    my @regions;
+    do {
+        push @regions, $f;
+    } while ($f = $f->parent);
+
+    for $f (reverse @regions) {
+        my $new = Jifty->web->get_region( join '-', grep {$_} Jifty->web->qualified_region, $f->name );
+
+        # Arguments can be complex mapped hash values.  Get their
+        # real values by mapping.
+        my %defaults = %{$f->arguments || {}};
+        for (keys %defaults) {
+            my ($key, $value) = Jifty::Request::Mapper->map(destination => $_, source => $defaults{$_});
+            delete $defaults{$_};
+            $defaults{$key} = $value;
+        }
+
+        $new ||= Jifty::Web::PageRegion->new(
+            name           => $f->name,
+            path           => $f->path,
+            region_wrapper => $f->wrapper,
+            parent         => Jifty->web->current_region,
+            defaults       => \%defaults,
+        );
+        $new->enter;
+    }
+
+    # Stuff the rendered region into the XML
+    $writer->startTag( "fragment", id => Jifty->web->current_region->qualified_name );
+    my %args = %{ Jifty->web->current_region->arguments };
+    $writer->dataElement( "argument", $args{$_}, name => $_) for sort keys %args;
+    $writer->cdataElement( "content", Jifty->web->current_region->as_string );
+    $writer->endTag();
+
+    Jifty->web->current_region->exit while Jifty->web->current_region;
+}
+
+my %results = Jifty->web->response->results;
+for (keys %results) {
+    $writer->startTag("result", moniker => $_, class => $results{$_}->action_class);
+    $writer->dataElement("success", $results{$_}->success);
+
+    $writer->dataElement("message", $results{$_}->message) if $results{$_}->message;
+    $writer->dataElement("error", $results{$_}->error) if $results{$_}->error;
+
+    my %warnings = $results{$_}->field_warnings;
+    my %errors   = $results{$_}->field_errors;
+    my %fields; $fields{$_}++ for keys(%warnings), keys(%errors);
+    for (sort keys %fields) {
+        next unless $warnings{$_} or $errors{$_};
+        $writer->startTag("field", name => $_);
+        $writer->dataElement("warning", $warnings{$_}) if $warnings{$_};
+        $writer->dataElement("error", $errors{$_}) if $errors{$_};
+        $writer->endTag();
+    }
+
+    # XXX TODO: Hack because we don't have a good way to serialize
+    # Jifty::DBI::Record's yet, which are technically circular data
+    # structures at some level (current_user of a
+    # current_user->user_object is itself)
+    use Scalar::Util qw(blessed);
+    my $content = $results{$_}->content;
+
+    sub stripkids {
+        my $top = shift;
+        if ( not ref $top ) { return $top }
+        elsif (
+            blessed($top)
+            and (  $top->isa("Jifty::DBI::Record")
+                or $top->isa("Jifty::DBI::Collection") )
+            )
+        {
+            return undef;
+        } elsif ( ref $top eq 'HASH' ) {
+            foreach my $item ( keys %$top ) {
+                $top->{$item} = stripkids( $top->{$item} );
+            }
+        } elsif ( ref $top eq 'ARRAY' ) {
+            for ( 0 .. $#{$top} ) {
+                $top->[$_] = stripkids( $top->[$_] );
+            }
+        }
+        return $top;
+    }
+
+    $content = stripkids($content);
+    use XML::Simple;
+    $writer->raw(XML::Simple::XMLout($content, NoAttr => 1, RootName => "content", NoIndent => 1))
+      if keys %{$content};
+
+    $writer->endTag();
+}
+
+$writer->endTag();
+$r->content_type('text/xml; charset=utf-8');
+outs($output);
+}
+
+sub __jifty::webservices::yaml {
+    $r->content_type("text/x-yaml");
+    outs( Jifty::YAML::Dump( { Jifty->web->response->results } ) );
+}
+
+sub _elements::header {
+    my ($title) = get(qw(title));
+    $r->content_type('text/html; charset=utf-8');
+    head {
+        with(
+            'http-equiv' => "content-type",
+            content      => "text/html; charset=utf-8"
+            ),
+            meta {};
+        with( name => 'robots', content => 'all' ), meta {};
+        title { _($title) };
+
+        Jifty->web->include_css;
+        Jifty->web->include_javascript;
+        }
+}
+
+sub _elements::keybindings {
+    with( id => "keybindings" ), div {};
+}
+
+sub _elements::menu {
+    my ($menu) = get(qw(menu));
+
+    # Default to the app menu
+    $menu ||= Jifty->web->navigation;
+    my @children = $menu->children;
+    if (@children) {
+        with( class => "menu" ), ul {
+            show( ".menu", item => $_ );
+            }
+    }
+
+}
+sub _elements::_menu {
+    my ($item) = get(qw(item));
+    my @kids = $item->children;
+    my @params;
+    if ( $item->active ) {
+        push @params, class => "active";
+    }
+
+    with(@params), li {
+
+        $item->as_link;
+
+        if (@kids) {
+            with( class => "submenu" ), ul {
+                show( ".menu", item => $_ ) for @kids;
+                }
+        };
+        }
+
+}
+
+sub _elements::nav {
+    my $top = Jifty->web->navigation;
+    $top->child( Home => url => "/", sort_order => 1 );
+    if ( Jifty->config->framework('AdminMode') ) {
+        $top->child(
+            Administration =>
+                url        => "/__jifty/admin/",
+            sort_order => 998
+        );
+        $top->child(
+            OnlineDocs =>
+                url    => "/__jifty/online_docs/",
+            label      => 'Online docs',
+            sort_order => 999
+        );
+    }
+    return ();
+}
+
+sub _elements::page_nav {
+    if ( @{ Jifty->web->page_navigation->children } ) {
+        with( class => "page_nav" ), div {
+            show( _elements::menu, menu => Jifty->web->page_navigation );
+            }
+    }
+}
+
+sub _elements::sidebar {
+    with( id => "salutation" ), div {
+        if (    Jifty->web->current_user->id
+            and Jifty->web->current_user->user_object )
+        {
+            my $u      = Jifty->web->current_user->user_object;
+            my $method = $u->_brief_description;
+            _( 'Hiya, %1.', $u->$method() );
+        } else {
+            _(q{You're not currently signed in.});
+        }
+    };
+    with( id => "navigation" ), div {
+        show( '_elements::menu', menu => Jifty->web->navigation );
+        }
+}
+
+sub _elements::wrapper { 
+% Jifty->handler->stash->{'in_body'} = 0;
+my ( $title ) = get(qw(title));
+# First we set up the header. 
+# now that we've printed out the header, we're inside the body, so it's safe to print
+# halo markers.
+Jifty->handler->stash->{'in_body'} = 1;
+outs('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">');
+with ( xmlns=> "http://www.w3.org/1999/xhtml" 'xml:lang'=>"en"), html {
+
+    with (title => $title), show (_elements::header);
+
+body {
+  with ( id => "headers"), div {
+    <%hyperlink( url => "/", label => _(Jifty->config->framework('ApplicationName')))%>
+    <h1 class="title"><% _($title) %>}
+  }
+  <& sidebar &>
+  with ( id => "content"), div {
+      with (name => 'content'), a{};
+ if (Jifty->config->framework('AdminMode') ) {
+with ( class => "warning admin_mode"), div {
+outs(_('Alert'). ':' . Jifty->web->tangent( label => _('Administration mode is enabled.') , url => '/__jifty/admin/'));
+}
+ }
+  <% Jifty->web->render_messages %>
+  <% $m->content |n%>
+  <& /_elements/keybindings &>
+  }
+  with ( id => "jifty-wait-message" style="display: none"), div {<%_('Loading...')%>}
+ Jifty::Mason::Halo->render_component_tree() if (Jifty->config->framework('DevelMode') );
+# This is required for jifty server push.  If you maintain your own
+# wrapper, make sure you have this as well.
+ if ( Jifty->config->framework('PubSub')->{'Enable'} && Jifty::Subs->list ) {
+script {outs('new Jifty.Subs({}).start();')};
+ }
+}
+}
+}
+
+sub autohandler {  # XXX TODO MOVE INTO DISPATCHER
+$r->content_type('text/html; charset=utf-8');
+
+if ($m->base_comp->path =~ m|/_elements/|) {
+    # Requesting an internal component by hand -- naughty
+    $m->redirect("/errors/requested_private_component");
+}
+$m->comp('/_elements/nav');
+}
+
+sub dhandler {
+    Jifty->log->error( "404: user tried to get to " . $m->dhandler_arg );
+    $r->header_out( Status => '404' );
+    with( title => _("Something's not quite right") ), wrapper => {
+
+        with( id => "overview" ),
+        div {
+            p {
+                join( " ",
+                    _("You got to a page that we don't think exists."),
+                    _("Anyway, the software has logged this error."),
+                    _("Sorry about this . ") );
+                }
+
+                p { hyperlink( url => " / ", label => _('Go back home...') ) }
+
+            }
+    };
+}
+
+sub index {
+    with( title => _('Welcome to your new Jifty application') ), wrapper {
+        with(
+            src => "/static/images/pony.jpg",
+            alt => _( 'You said you wanted a pony. (Source %1)',
+                'http://hdl.loc.gov/loc.pnp/cph.3c13461')
+            ),
+            img {};
+        }
+}
+

Modified: jifty/branches/template-declare/lib/Jifty/View/Declare/Handler.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/View/Declare/Handler.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/View/Declare/Handler.pm	Mon Nov 27 18:49:08 2006
@@ -52,7 +52,7 @@
     my $template   = pop @components;
 
     my $package =  join('::',$self->root_class,grep { $_ } @components);
-    Jifty::Util->require($package);
+     Jifty::Util->require($package) ;
     unless ( $package->isa('Jifty::View::Declare::Templates') ) {
         $self->log->error( "$package (" . $self->root_class . " / $templatename) isn't a valid template package." );
         return undef;

Modified: jifty/branches/template-declare/lib/Jifty/View/Declare/Templates.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/View/Declare/Templates.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/View/Declare/Templates.pm	Mon Nov 27 18:49:08 2006
@@ -8,7 +8,8 @@
 use base qw/Template::Declare/;
 our @EXPORT = qw(form hyperlink tangent redirect new_action form_submit form_next_page request get param current_user render_action);
 
-
+{
+no warnings qw/redefine/;
 sub form (&){
     my $code = shift;
     outs(Jifty->web->form->start);
@@ -16,7 +17,7 @@
     outs(Jifty->web->form->end);
     return ''
 }
-
+}
 
 sub hyperlink(@) {
     outs (Jifty->web->link(@_));


More information about the Jifty-commit mailing list