[Jifty-commit] r2217 - in
jifty/branches/template-declare/lib/Jifty/View: .
jifty-commit at lists.jifty.org
jifty-commit at lists.jifty.org
Wed Nov 29 09:49:44 EST 2006
Author: audreyt
Date: Wed Nov 29 09:49:43 2006
New Revision: 2217
Added:
jifty/branches/template-declare/lib/Jifty/View/Declare.pm
jifty/branches/template-declare/lib/Jifty/View/Declare/Base.pm
Removed:
jifty/branches/template-declare/lib/Jifty/View/Declare/BaseView.pm
Modified:
jifty/branches/template-declare/lib/Jifty/View/Declare/Handler.pm
Log:
* Shiny new class: Jifty::View::Declare. From its SYNOPSIS:
package MyApp::View;
use Jifty::View::Declare -base;
template 'index.html' => page {
b { "The Index" };
} 'Some Title';
* Jifty::View::Declare::Base now replaces ::BaseView as the new base class.
* Jifty::View::Handler now precompiles the ->has_template code to avoid double lookup.
Added: jifty/branches/template-declare/lib/Jifty/View/Declare.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/View/Declare.pm Wed Nov 29 09:49:43 2006
@@ -0,0 +1,31 @@
+package Jifty::View::Declare;
+use Jifty::View::Declare::Base ();
+
+use strict;
+use warnings;
+use constant BaseClass => 'Jifty::View::Declare::Base';
+
+=head1 SYNOPSIS
+
+ package MyApp::View;
+ use Jifty::View::Declare -base;
+
+ template 'index.html' => page {
+ b { "The Index" };
+ } 'Some Title';
+
+=cut
+
+sub import {
+ my ($class, $import) = @_;
+ ($import and $import eq '-base') or return;
+
+ no strict 'refs';
+ my $pkg = caller;
+ push @{ $pkg . '::ISA' }, BaseClass;
+
+ @_ = BaseClass;
+ goto &{BaseClass()->can('import')};
+}
+
+1;
Added: jifty/branches/template-declare/lib/Jifty/View/Declare/Base.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/View/Declare/Base.pm Wed Nov 29 09:49:43 2006
@@ -0,0 +1,1737 @@
+package Jifty::View::Declare::Base;
+
+use strict;
+use warnings;
+use vars qw( $r $m );
+use base qw/Jifty::View::Declare::Templates/;
+use Scalar::Defer;
+use Template::Declare::Tags;
+use Jifty::View::Declare::Templates;
+
+our @EXPORT = (@Jifty::View::Declare::Templates::EXPORT, @Template::Declare::Tags::EXPORT, 'page');
+our $r = defer { Jifty->handler->apache };
+our $m = defer { Jifty->web->mason };
+
+{
+no warnings 'redefine';
+sub show {
+ # Handle relative path here!
+ my $path = shift;
+ $path =~ s{^/}{};
+ Jifty::View::Declare::Templates->can('show')->($path, @_);
+}
+}
+
+# template 'foo' => page { ... } 'title';
+sub page (&;$) {
+ my $code = shift;
+ my $title = (@_ ? shift(@_) : 'Untitled');
+ sub {
+ $r->content_type('text/html; charset=utf-8');
+ show('/_elements/nav');
+ with( title => _($title) ), wrapper($code);
+ };
+};
+
+template '_elements/nav' => sub {
+ 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 wrapper (&) {
+ my $content_code = shift;
+
+ Jifty->handler->stash->{'in_body'} = 0;
+ my ($title) = get_current_attr(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') )
+ );
+ with( class => "title" ), h1 { $title };
+ }
+ };
+ show('/_elements/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;
+ &$content_code;
+ show('/_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();') };
+ }
+ }
+ }
+};
+
+template '_elements/sidebar' => sub {
+ 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 {
+ my $menu = Jifty->web->navigation;
+ my @children = $menu->children;
+ if (@children) {
+ with( class => "menu" ), ul {
+ render_menu($_) for @children;
+ }
+ }
+ };
+};
+
+sub render_menu {
+ my $item = shift;
+ my @kids = $item->children;
+ my @params;
+ if ( $item->active ) {
+ push @params, class => "active";
+ }
+
+ with(@params), li {
+
+ outs($item->as_link);
+
+ if (@kids) {
+ with( class => "submenu" ), ul {
+ render_menu($_) for @kids;
+ }
+ }
+ }
+}
+
+template '_elements/header' => sub {
+ my ($title) = get_current_attr(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;
+ }
+};
+
+template '__jifty/subs' => sub {
+ 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>$/$whitespace/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();
+ }
+ );
+}
+
+template '__jifty/admin/_elements/nav' => sub {
+ 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;
+};
+
+template '__jifty/admin/action/dhandler' => sub {
+ 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, $_ );
+ }
+
+ Jifty->web->form->submit( label => _("Run the action") );
+ };
+
+ h2 { _('Done?') };
+ hyperlink(
+ url => "/__jifty/admin/",
+ label => _('Back to the admin console')
+ );
+
+ }
+};
+
+template '__jifty/admin/autohandler' => sub {
+
+# 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('/__jifty/admin/elements/nav'); # XXX TODO hm. should be in dispatcher.
+};
+
+template '__jifty/admin/fragments/list/list' => sub {
+ 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
+#
+template '__jifty/admin/fragments/list/new_item' => sub {
+ 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' },
+ },
+ },
+ ]
+ )
+
+};
+
+template '__jifty/admin/fragments/list/search' => sub {
+ 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 {};
+ }
+};
+
+template '__jifty/admin/fragments/list/update' => sub {
+ 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 {};
+ };
+};
+
+template '__jifty/admin/fragments/list/view' => sub {
+ 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 {};
+ };
+
+};
+
+template '__jifty/admin/index' => sub {
+ 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'
+ );
+ }
+};
+
+template '__jifty/admin/model/dhandler' => sub {
+ 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'
+ );
+
+ }
+};
+
+template '__jifty/autocomplete.xml' => sub {
+
+ # 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} };
+ }
+ }
+ };
+ };
+};
+
+template '__jifty/css/dhandler' => sub {
+ 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;
+};
+
+template '__jifty/empty' => sub {
+ '';
+};
+
+template '__jifty/error/_elements/error_text' => sub {
+ my ($error) = get(qw(error));
+ 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 do have is :"
+ );
+ };
+
+ blockquote {
+ b { $error };
+ };
+
+ 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 {
+ hyperlink(
+ url => "/",
+ label => 'Head on back home'
+ );
+ _("for now, and try to forget that we let you down.");
+ };
+};
+
+=begin TODO
+
+ 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(
+ (
+ ' '
+ 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(
+ (
+ ' '
+ x $indent
+ )
+ );
+ $m->print("$1<br />");
+ $indent++;
+ }
+ }
+ elsif (
+ $prev =~ /^$parent\::(.*::)/ )
+ {
+ my $foo = $1;
+ while ( $foo =~ s/::// ) {
+ $indent--;
+ }
+ }
+ $m->print(
+ (
+ ' ' 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::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::page_nav {
+ if ( @{ Jifty->web->page_navigation->children } ) {
+ with( class => "page_nav" ), div {
+ show( _elements::menu,
+ menu => Jifty->web->page_navigation );
+ }
+ }
+ }
+
+
+ }
+
+ 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...')
+ );
+ }
+
+ }
+ };
+ }
+
+=end TODO
+
+=cut
+
+template 'index.html' => page {
+ with(
+ src => "/static/images/pony.jpg",
+ alt => _(
+ 'You said you wanted a pony. (Source %1)',
+ 'http://hdl.loc.gov/loc.pnp/cph.3c13461'
+ )
+ ), img {};
+} 'Welcome to your new Jifty application';
+
+1;
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 Wed Nov 29 09:49:43 2006
@@ -14,7 +14,7 @@
sub show {
my $self = shift;
my $package = shift;
- my $template = shift;
+ my $code_template = shift;
no warnings qw/redefine/;
local *Jifty::Web::out = sub {
@@ -23,7 +23,7 @@
};
local $Template::Declare::Tags::BUFFER = '';
- print STDOUT $package->show($template);
+ print STDOUT $package->show($code_template);
return undef;
}
@@ -43,40 +43,49 @@
would become
- Wifty::UI::admin::users, new
+ Wifty::View::admin::users, new
=cut
sub resolve_template {
- my $self = shift;
- my $templatename = shift; # like /admin/ui/new
+ my $self = shift;
+ my $template_name = shift; # like /admin/ui/new
- my @components = split( '/', $templatename );
+ my @components = split( '/', $template_name );
my $template = pop @components;
+ my $package;
- my $package = join('::',$self->root_class,grep { $_ } @components);
- $package->require;
+ REQUIRE_PACKAGE: {
+ $package = join('::', $self->root_class, grep { $_ } @components);
+ $package->require;
+
+ if ($UNIVERSAL::require::ERROR =~ /^Can't locate/) {
+ $self->log->debug($UNIVERSAL::require::ERROR);
+
+ # It's possible that /admin/ui/new is defined in admin, instead of admin::ui
+ if (@components) {
+ $template = pop(@components) . '/' . $template;
+ redo REQUIRE_PACKAGE;
+ }
- if ($UNIVERSAL::require::ERROR =~ /^Can't locate/) {
- $self->log->debug($UNIVERSAL::require::ERROR);
- return undef;
+ return undef;
+ }
}
unless ( $package->isa('Jifty::View::Declare::Templates') ) {
- $self->log->error( "$package (" . $self->root_class . " / $templatename) isn't a valid template package." );
+ $self->log->error( "$package (" . $self->root_class . " / $template_name) isn't a valid template package." );
return undef;
}
- unless ( $package->can('has_template') && $package->has_template($template) ) {
+
+ if ( $package->can('has_template') and my $code_template = $package->has_template($template) ) {
+ return ( $package, $code_template );
+ }
+ else {
$self->log->warn("$package has no template $template.");
return undef;
-
}
-
- return ( $package, $template );
-
}
1;
-
More information about the Jifty-commit
mailing list