]> git.decadent.org.uk Git - maypole.git/commitdiff
moved ex to examples, fix to edit template
authorAaron Trevena <aaron.trevena@gmail.com>
Thu, 10 Aug 2006 13:40:40 +0000 (13:40 +0000)
committerAaron Trevena <aaron.trevena@gmail.com>
Thu, 10 Aug 2006 13:40:40 +0000 (13:40 +0000)
git-svn-id: http://svn.maypole.perl.org/Maypole/trunk@520 48953598-375a-da11-a14b-00016c27c3ee

76 files changed:
Changes
MANIFEST
ex/BeerDB.pm [deleted file]
ex/BeerDB/Base.pm [deleted file]
ex/BeerDB/Beer.pm [deleted file]
ex/beerdb.sql [deleted file]
ex/fancy_example/BeerDB.pm [deleted file]
ex/fancy_example/BeerDB/Base.pm [deleted file]
ex/fancy_example/BeerDB/Beer.pm [deleted file]
ex/fancy_example/BeerDB/Brewery.pm [deleted file]
ex/fancy_example/BeerDB/Drinker.pm [deleted file]
ex/fancy_example/beerdb.sql [deleted file]
ex/fancy_example/templates/custom/addnew [deleted file]
ex/fancy_example/templates/custom/display_inputs [deleted file]
ex/fancy_example/templates/custom/display_search_inputs [deleted file]
ex/fancy_example/templates/custom/edit [deleted file]
ex/fancy_example/templates/custom/header [deleted file]
ex/fancy_example/templates/custom/maypole.css [deleted file]
ex/fancy_example/templates/custom/metadata [deleted file]
ex/fancy_example/templates/custom/search_form [deleted file]
ex/fancy_example/templates/factory/addnew [deleted file]
ex/fancy_example/templates/factory/edit [deleted file]
ex/fancy_example/templates/factory/footer [deleted file]
ex/fancy_example/templates/factory/frontpage [deleted file]
ex/fancy_example/templates/factory/header [deleted file]
ex/fancy_example/templates/factory/list [deleted file]
ex/fancy_example/templates/factory/login [deleted file]
ex/fancy_example/templates/factory/macros [deleted file]
ex/fancy_example/templates/factory/maypole [deleted file]
ex/fancy_example/templates/factory/maypole.css [deleted file]
ex/fancy_example/templates/factory/navbar [deleted file]
ex/fancy_example/templates/factory/pager [deleted file]
ex/fancy_example/templates/factory/search_form [deleted file]
ex/fancy_example/templates/factory/search_form_recursive [deleted file]
ex/fancy_example/templates/factory/title [deleted file]
ex/fancy_example/templates/factory/view [deleted file]
examples/BeerDB.pm [new file with mode: 0644]
examples/BeerDB/Base.pm [new file with mode: 0644]
examples/BeerDB/Beer.pm [new file with mode: 0644]
examples/beerdb.sql [new file with mode: 0644]
examples/fancy_example/BeerDB.pm [new file with mode: 0644]
examples/fancy_example/BeerDB/Base.pm [new file with mode: 0644]
examples/fancy_example/BeerDB/Beer.pm [new file with mode: 0644]
examples/fancy_example/BeerDB/Brewery.pm [new file with mode: 0644]
examples/fancy_example/BeerDB/Drinker.pm [new file with mode: 0644]
examples/fancy_example/beerdb.sql [new file with mode: 0644]
examples/fancy_example/templates/custom/addnew [new file with mode: 0644]
examples/fancy_example/templates/custom/display_inputs [new file with mode: 0644]
examples/fancy_example/templates/custom/display_search_inputs [new file with mode: 0644]
examples/fancy_example/templates/custom/edit [new file with mode: 0644]
examples/fancy_example/templates/custom/header [new file with mode: 0644]
examples/fancy_example/templates/custom/maypole.css [new file with mode: 0644]
examples/fancy_example/templates/custom/metadata [new file with mode: 0644]
examples/fancy_example/templates/custom/search_form [new file with mode: 0644]
examples/fancy_example/templates/factory/addnew [new file with mode: 0644]
examples/fancy_example/templates/factory/edit [new file with mode: 0644]
examples/fancy_example/templates/factory/footer [new file with mode: 0644]
examples/fancy_example/templates/factory/frontpage [new file with mode: 0644]
examples/fancy_example/templates/factory/header [new file with mode: 0644]
examples/fancy_example/templates/factory/list [new file with mode: 0644]
examples/fancy_example/templates/factory/login [new file with mode: 0644]
examples/fancy_example/templates/factory/macros [new file with mode: 0644]
examples/fancy_example/templates/factory/maypole [new file with mode: 0644]
examples/fancy_example/templates/factory/maypole.css [new file with mode: 0644]
examples/fancy_example/templates/factory/navbar [new file with mode: 0644]
examples/fancy_example/templates/factory/pager [new file with mode: 0644]
examples/fancy_example/templates/factory/search_form [new file with mode: 0644]
examples/fancy_example/templates/factory/search_form_recursive [new file with mode: 0644]
examples/fancy_example/templates/factory/title [new file with mode: 0644]
examples/fancy_example/templates/factory/view [new file with mode: 0644]
lib/Maypole/Manual/About.pod
lib/Maypole/View/TT.pm
lib/Maypole/templates/factory/edit
t/01basics.t
t/crud.t
t/db_colinfo.t

diff --git a/Changes b/Changes
index c7efd8aa7755c3f14c7664710c639098b81aa070..c4cc7dbfccdd4990685c1d25cc31f106b9035d42 100644 (file)
--- a/Changes
+++ b/Changes
@@ -2,7 +2,9 @@ This file documents the revision history for Perl extension Maypole.
 For information about current developments and future releases, see:
     http://maypole.perl.org/?TheRoadmap
 
-2.11 
+2.11 Mon 31 July 2006
+
+SVN revision 519
 
 Deprecated:
     Directly accessing the attributes of the request object, or the parameters 
index d5515b9fd6253edc1a6f2e2ef9e84d8e3330e105..623a93477e7fcfec0ca2fae3be72ab50f9a9d331 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,22 +1,22 @@
 Changes
-ex/BeerDB.pm
-ex/BeerDB/Base.pm
-ex/BeerDB/Beer.pm
-ex/beerdb.sql
-ex/fancy_example/BeerDB.pm
-ex/fancy_example/beerdb.sql
-ex/fancy_example/BeerDB/Base.pm
-ex/fancy_example/BeerDB/Beer.pm
-ex/fancy_example/BeerDB/Brewery.pm
-ex/fancy_example/BeerDB/Drinker.pm
-ex/fancy_example/templates/custom/addnew  
-ex/fancy_example/templates/custom/display_inputs  
-ex/fancy_example/templates/custom/display_search_inputs  
-ex/fancy_example/templates/custom/edit  
-ex/fancy_example/templates/custom/header  
-ex/fancy_example/templates/custom/maypole.css  
-ex/fancy_example/templates/custom/metadata  
-ex/fancy_example/templates/custom/search_form
+examples/BeerDB.pm
+examples/BeerDB/Base.pm
+examples/BeerDB/Beer.pm
+examples/beerdb.sql
+examples/fancy_example/BeerDB.pm
+examples/fancy_example/beerdb.sql
+examples/fancy_example/BeerDB/Base.pm
+examples/fancy_example/BeerDB/Beer.pm
+examples/fancy_example/BeerDB/Brewery.pm
+examples/fancy_example/BeerDB/Drinker.pm
+examples/fancy_example/templates/custom/addnew  
+examples/fancy_example/templates/custom/display_inputs  
+examples/fancy_example/templates/custom/display_search_inputs  
+examples/fancy_example/templates/custom/edit  
+examples/fancy_example/templates/custom/header  
+examples/fancy_example/templates/custom/maypole.css  
+examples/fancy_example/templates/custom/metadata  
+examples/fancy_example/templates/custom/search_form
 lib/Apache/MVC.pm
 lib/CGI/Maypole.pm
 lib/CGI/Untaint/Maypole.pm
diff --git a/ex/BeerDB.pm b/ex/BeerDB.pm
deleted file mode 100644 (file)
index e0b2894..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-package BeerDB;
-use Maypole::Application;
-use Class::DBI::Loader::Relationship;
-
-sub debug { $ENV{BEERDB_DEBUG} || 0 }
-# This is the sample application.  Change this to the path to your
-# database. (or use mysql or something)
-use constant DBI_DRIVER => 'SQLite';
-use constant DATASOURCE => $ENV{BEERDB_DATASOURCE} || 't/beerdb.db';
-
-
-BEGIN {
-    my $dbi_driver = DBI_DRIVER;
-    if ($dbi_driver =~ /^SQLite/) {
-        die sprintf "SQLite datasource '%s' not found, correct the path or "
-            . "recreate the database by running Makefile.PL", DATASOURCE
-            unless -e DATASOURCE;
-        eval "require DBD::SQLite";
-        if ($@) {
-            eval "require DBD::SQLite2" and $dbi_driver = 'SQLite2';
-        }
-    }
-    BeerDB->setup(join ':', "dbi", $dbi_driver, DATASOURCE);
-}
-
-# Give it a name.
-BeerDB->config->application_name('The Beer Database');
-
-# Change this to the root of the web site for your maypole application.
-BeerDB->config->uri_base( $ENV{BEERDB_BASE} || "http://localhost/beerdb/" );
-
-# Change this to the htdoc root for your maypole application.
-
-my @root=  ('t/templates'); 
-push @root,$ENV{BEERDB_TEMPLATE_ROOT} if ($ENV{BEERDB_TEMPLATE_ROOT});
-BeerDB->config->template_root( [@root] ); 
-# Specify the rows per page in search results, lists, etc : 10 is a nice round number
-BeerDB->config->rows_per_page(10);
-
-# Handpumps should not show up.
-BeerDB->config->display_tables([qw[beer brewery pub style]]);
-BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
-BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
-BeerDB::Beer->untaint_columns(
-    printable => [qw/abv name price notes url/],
-    integer => [qw/style brewery score/],
-    date =>[ qw/tasted/],
-);
-BeerDB::Pub->untaint_columns(printable => [qw/name notes url/]);
-
-# Required Fields
-BeerDB->config->{brewery}{required_cols} = [qw/name/];
-BeerDB->config->{style}{required_cols} = [qw/name/];
-BeerDB->config->{beer}{required_cols} = [qw/brewery name price/];
-BeerDB->config->{pub}{required_cols} = [qw/name/];
-
-BeerDB->config->{loader}->relationship($_) for (
-    "a brewery produces beers",
-    "a style defines beers",
-    "a pub has beers on handpumps");
-
-# For testing classmetadata
-sub BeerDB::Beer::classdata :Exported {};
-sub BeerDB::Beer::list_columns  { return qw/score name price style brewery url/};
-
-1;
diff --git a/ex/BeerDB/Base.pm b/ex/BeerDB/Base.pm
deleted file mode 100644 (file)
index 75ed338..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package BeerDB::Base;
-use strict;
-use warnings;
-
-sub floob {}
-
-1;
diff --git a/ex/BeerDB/Beer.pm b/ex/BeerDB/Beer.pm
deleted file mode 100644 (file)
index d7de346..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package BeerDB::Beer;
-use strict;
-use warnings;
-
-# do this to test we get the expected @ISA after setup_model()
-use base 'BeerDB::Base';
-
-sub fooey : Exported {}
-
-1;
diff --git a/ex/beerdb.sql b/ex/beerdb.sql
deleted file mode 100644 (file)
index 0c6a0df..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-CREATE TABLE style (
-    id integer primary key auto_increment,
-    name varchar(60),
-    notes text
-);
-
-CREATE TABLE pub (
-    id integer primary key auto_increment,
-    name varchar(60),
-    url varchar(120),
-    notes text
-);
-
-CREATE TABLE handpump (
-    id integer primary key auto_increment,
-    beer integer,
-    pub integer
-);
-
-CREATE TABLE beer (
-    id integer primary key auto_increment,
-    brewery integer,
-    style integer,
-    name varchar(30),
-    url varchar(120),
-    score integer(2),
-    price varchar(12),
-    abv varchar(10),
-    notes text,
-       tasted date
-);
-
-CREATE TABLE brewery (
-    id integer  primary key auto_increment,
-    name varchar(30),
-    url varchar(50),
-    notes text
-);
diff --git a/ex/fancy_example/BeerDB.pm b/ex/fancy_example/BeerDB.pm
deleted file mode 100644 (file)
index cb72574..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-package BeerDB;
-use Maypole::Application;
-use Class::DBI::Loader::Relationship;
-
-sub debug { $ENV{BEERDB_DEBUG} || 0 }
-# This is the sample application.  Change this to the path to your
-# database. (or use mysql or something)
-use constant DBI_DRIVER => 'SQLite';
-use constant DATASOURCE => '/home/peter/Desktop/maypolebeer/beerdb'; 
-
-BeerDB->config->model('BeerDB::Base'); 
-
-BeerDB->setup("dbi:mysql:beerdb",'root', '');
-
-# Give it a name.
-BeerDB->config->application_name('The Beer Database');
-
-# Change this to the root of the web site for your maypole application.
-BeerDB->config->uri_base( $ENV{BEERDB_BASE} || "http://localhost/beerdb/" );
-
-# Change this to the htdoc root for your maypole application.
-
-my @root=  ('/home/peter/Desktop/maypolebeer/templates'); 
-push @root,$ENV{BEERDB_TEMPLATE_ROOT} if ($ENV{BEERDB_TEMPLATE_ROOT});
-BeerDB->config->template_root( [@root] ); 
-# Specify the rows per page in search results, lists, etc : 10 is a nice round number
-BeerDB->config->rows_per_page(10);
-
-# Let TT templates recursively include  themselves
-BeerDB->config->{view_options} = { RECURSION => 1, };
-
-# Handpumps should not show up.
-BeerDB->config->display_tables([qw[beer brewery pub style drinker pint person]]);
-# Access handpumps if want
-BeerDB->config->ok_tables([ @{BeerDB->config->display_tables}, qw[handpump]]);
-
-BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
-BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
-BeerDB::Beer->untaint_columns(
-    printable => [qw/abv name price notes/],
-    integer => [qw/style brewery score/],
-    date =>[ qw/tasted/],
-);
-BeerDB::Pub->untaint_columns(printable => [qw/name notes url/]);
-BeerDB::Drinker->untaint_columns( printable => [qw/handle created/] );
-BeerDB::Pint->untaint_columns( printable => [qw/date_and_time/]);
-
-
-# Required Fields
-BeerDB->config->{brewery}{required_cols} = [qw/name url/];
-BeerDB->config->{style}{required_cols} = [qw/name/];
-BeerDB->config->{beer}{required_cols} = [qw/brewery name price/];
-BeerDB->config->{pub}{required_cols} = [qw/name/];
-BeerDB->config->{drinker}{required_cols} = [qw/handle person/];
-BeerDB->config->{pint}{required_cols} = [qw/drinker handpump/]; 
-BeerDB->config->{person}{required_cols} = [qw/first_name sur_name dob email/];
-
-# Columns to display 
-sub BeerDB::Handpump::display_columns { qw/pub beer/ }
-
-BeerDB->config->{loader}->relationship($_) for (
-    "a brewery produces beers",
-    "a style defines beers",
-    "a pub has beers on handpumps",
-    "a handpump defines pints",
-    "a drinker drinks pints",);
-
-# For testing classmetadata
-#sub BeerDB::Beer::classdata :Exported {};
-sub BeerDB::Beer::list_columns  { return qw/score name price style brewery/};
-
-sub BeerDB::Handpump::stringify_self { 
-       my $self = shift; 
-       return $self->beer . " @ " . $self->pub;
-}
-
-
-1;
diff --git a/ex/fancy_example/BeerDB/Base.pm b/ex/fancy_example/BeerDB/Base.pm
deleted file mode 100644 (file)
index aaafce1..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package BeerDB::Base;
-use base qw/Maypole::Model::CDBI/;
-use strict;
-use warnings;
-use Data::Dumper;
-
-# Overide list to add display_columns to cgi  
-# Perhaps do this in AsForm?
-sub list : Exported {
-       use Data::Dumper;
-       my ($self, $r) = @_;
-       $self->SUPER::list($r);
-       my %cols =  map { $_ => 1 } $self->columns, $self->display_columns;
-       my @cols = keys %cols;
-       $r->template_args->{classmetadata}{cgi} = { $self->to_cgi(@cols) }; 
-}
-
-# Override view to make inputs and process form to add to related 
-sub view : Exported {
-    my ($self, $r, $obj) = @_;
-    $self->_croak( "Object method only") unless $obj;
-
-    if ($r->params->{submit}) {
-        my @related  = $obj->add_to_from_cgi($r, { required => [$self->related ]});
-        if (my $errs = $obj->cgi_update_errors) {
-            $r->template_args->{errors} = $errs;
-        }
-    }
-
-    # Inputs to add to related on the view page
-       # Now done on the view template 
-       # my %cgi = $self->to_cgi($self->related);
-       #$r->template_args->{classmetadata}{cgi} =  \%cgi ;
-}
-
-
-# Template switcheroo bug bit me -- was seeing view page but the view action was never 
-# being executed after an edit.
-sub do_edit : Exported {
-       my ($self, $r) = (shift, shift);
-       $self->SUPER::do_edit($r, @_);
-       if (my $obj = $r->object) {
-               my $url = $r->config->uri_base . "/" . $r->table . "/view/" . $obj->id;
-               $r->redirect_request(url => $url);
-       }
-}
-
-sub metadata: Exported {}
-       
-
-1;
diff --git a/ex/fancy_example/BeerDB/Beer.pm b/ex/fancy_example/BeerDB/Beer.pm
deleted file mode 100644 (file)
index d7de346..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package BeerDB::Beer;
-use strict;
-use warnings;
-
-# do this to test we get the expected @ISA after setup_model()
-use base 'BeerDB::Base';
-
-sub fooey : Exported {}
-
-1;
diff --git a/ex/fancy_example/BeerDB/Brewery.pm b/ex/fancy_example/BeerDB/Brewery.pm
deleted file mode 100644 (file)
index ad99483..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package BeerDB::Brewery;
-use strict;
-use warnings;
-
-use Data::Dumper;
-
-sub display_columns { qw/name url beers/ } # note has_man beers
-sub list_columns { qw/name url/ } 
-
-1;
diff --git a/ex/fancy_example/BeerDB/Drinker.pm b/ex/fancy_example/BeerDB/Drinker.pm
deleted file mode 100644 (file)
index db798fd..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-package BeerDB::Drinker;
-use strict;
-use warnings;
-
-use Data::Dumper;
-
-__PACKAGE__->columns('Stringify' => qw/handle/);
-
-# A drinker is a person but we do not want to select who that person is 
-# from a list because this is a 1:1 relationship rather than a M:1. 
-# The no_select option tells AsForm not to bother making a select box
-
-__PACKAGE__->has_a(person => 'BeerDB::Person', no_select => 1);
-
-# Drinker drinks many beers at pubs if they are lucky. I like to specify the
-# name of the foreign key unless i can control the order that the
-# cdbi classes are created. CDBI does not guess very well the fk column.
-
-#__PACKAGE__->has_many(pints => 'BeerDB::Pint', 'drinker');
-
-# When we create a drinker we want to create a person as well
-# So tell AsForm to display the person inputs too.
-
-sub display_columns { qw/person handle/ }
-sub list_columns { qw/person handle/ }
-# AsForm and templates may check for search_colums when making 
-#sub search_columns { qw/person handle/ }
-
-# We need to tweak the cgi inputs a little. 
-# Since list is where addnew is, override that.
-# Person is a has_a rel and AsForm wont make foreign inputs automatically so
-# we manually do it.
-
-sub list : Exported {
-       my ($self, $r) = @_;
-       $self->SUPER::list($r);
-       my %cgi = $self->to_cgi;
-       $cgi{person} = $self->to_field('person', 'foreign_inputs');
-       $r->template_args->{classmetadata}{cgi} = \%cgi;
-       #$r->template_args->{classmetadata}{search_cgi} = $self->search_inputs;
-}
-
-
-       
-
-#sub foreign_input_delimiter { '__IMODDD__'}
-
-1;
diff --git a/ex/fancy_example/beerdb.sql b/ex/fancy_example/beerdb.sql
deleted file mode 100644 (file)
index 6089c94..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-CREATE TABLE style (
-    id integer primary key auto_increment,
-    name varchar(60),
-    notes text
-);
-
-CREATE TABLE pub (
-    id integer primary key auto_increment,
-    name varchar(60),
-    url varchar(120),
-    notes text
-);
-
-CREATE TABLE handpump (
-    id integer primary key auto_increment,
-    beer integer,
-    pub integer
-);
-
-CREATE TABLE beer (
-    id integer primary key auto_increment,
-    brewery integer,
-    style integer,
-    name varchar(30),
-    score integer(2),
-    price varchar(12),
-    abv varchar(10),
-    notes text,
-       tasted date
-);
-
-CREATE TABLE brewery (
-    id integer  primary key auto_increment,
-    name varchar(30),
-    url varchar(50),
-    notes text
-);
-
-CREATE TABLE drinker (
-  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
-  person INTEGER UNSIGNED NOT NULL,
-  handle VARCHAR(20) NOT NULL,
-  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  PRIMARY KEY(id),
-  INDEX drinker_FKIndex1(person)
-);
-
-CREATE TABLE person (
-  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
-  first_name VARCHAR(50) NULL,
-  sur_name VARCHAR(50) NULL,
-  dob DATE NULL,
-  username VARCHAR(20) NULL,
-  password VARCHAR(20) NULL,
-  email VARCHAR(255) NULL,
-  PRIMARY KEY(id)
-);
-
-CREATE TABLE pint (
-  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
-  drinker INTEGER UNSIGNED NOT NULL,
-  handpump INTEGER UNSIGNED NOT NULL,
-  date_and_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  PRIMARY KEY(id)
-);
-
-
diff --git a/ex/fancy_example/templates/custom/addnew b/ex/fancy_example/templates/custom/addnew
deleted file mode 100644 (file)
index 7053240..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[%#
-
-=head1 addnew
-
-This is the interface to adding a new instance of an object. (or a new
-row in the database, if you want to look at it that way) It displays a
-form containing a list of HTML components for each of the columns in the
-table.
-
-=cut
-
-#%]
-[% tbl = classmetadata.table; %]
-
-<div id="addnew">
-<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
-<fieldset>
-<legend>Add a new [% config.TABLES.$tbl.singular || tbl | ucfirst | replace('_',' '); %] </legend>
-       [% INCLUDE display_inputs; %]
-    <input type="submit" name="create" value="create" />
-    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
-</fieldset>
-</form>
-</div>
diff --git a/ex/fancy_example/templates/custom/display_inputs b/ex/fancy_example/templates/custom/display_inputs
deleted file mode 100644 (file)
index 6baf703..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-[%# 
-
-=head1 display_inputs
-
-This *RECURSIVELY* displays inputs for a hash of html elements
-
-Vars it needs: 
-   classmetadata-- the hash of bunch of data:
-   cgi -- inputs keyed on column names
-   table -- table inputs are for
-   columns -- list  in order want displayed inputs
-   colnames -- hash of what to label inputs
-   
-errors          -- hash of errors keyed on columns 
-
-
-TODO -- make it recognize a general submit button for redisplaying
-values on errors
-
-=cut
-
-#
-%]
-
-[% # some variables
-   foreign    = []; 
-   names      = [];
-   # get hash of related classes keyed on accessor for Foreign Inputs
-   USE this   = Class(classmetadata.name); 
-   tbl = classmetadata.table;
-   required = { }; 
-   FOR c IN request.config.$tbl.required_cols;
-        required.$c = 1;
-   END;
-
-%]     
-
-[% 
-SET heading_shown = 0; 
-FOR col = classmetadata.columns;  
-       NEXT IF !classmetadata.cgi.$col;
-       NEXT IF col == "id" OR col == classmetadata.table _ "_id";
-       # Display foreign inputs last 
-       IF (mykeys = classmetadata.cgi.$col.keys); 
-                       foreign.push(col);
-                       names.push(classmetadata.colnames.$col);
-                       NEXT;
-       END;
-    IF ! heading_shown; 
-       heading = classmetadata.moniker | ucfirst; 
-               "<h4> $heading </h4>";
-       SET heading_shown = 1; 
-    END;
-%]
-
-[%  # Base case starts here 
-
-       SET elem = classmetadata.cgi.$col; #.clone; # not sure why clone
-       IF elem.type == 'hidden'; 
-               elem.as_XML;
-               NEXT;
-       ELSIF  cgi_params;
-               param_col = col_prefix _ col;
-               IF elem.tag == "textarea";
-                       elem = elem.push_content(cgi_params.$param_col);
-               ELSIF elem.tag == "select";
-                       oldval = set_selected(elem, cgi_params.$col);
-               ELSE;
-                       oldval = elem.attr("value", cgi_params.$param_col);
-               END;
-       END;
-%]
-
-       <label>
-               [% indicator = '';
-           SET indicator = '*' IF (required.$col); 
-        %]
-               <span class="field">
-                   [% indicator _ classmetadata.colnames.$col || 
-                       col | replace('_',' ') | ucfirst  %] 
-               </span>
-               [% elem.as_XML; %]
-       </label>
-
-       [% IF errors.$col %]
-               <span class="error">[% errors.$col | html  %]</span>
-       [% END %]
-[% END; %]
-
-<!-- Display the differnt component inputs --> 
-
-[%     USE this = Class(classmetadata.name); 
-       FOR col IN foreign; 
-               # has_many mapping throws a stick in our spokes because related_class returns the mapped 
-               # class. Sometimes we just want the has_many class. 
-
-        # In case of Pub Handpumps maps to Beer and we want to add Handpump to Pub, we dont 
-               # want the mapped data .
-        # In case of "Create New Handpump" -- we want the mapped data probably so we get
-        # Beer inputs and Pub select box.
-
-               fclass_rel_meta = this.related_meta(request, col);
-        fclass = fclass_rel_meta.foreign_class; # ignor args.mapping
-               fclass_meta = this.get_classmetadata(fclass);
-               fclass_meta.cgi = classmetadata.cgi.$col;
- #       USE Dumper; Dumper.dump(fclass_meta);
-               INCLUDE display_inputs
-                       col_prefix = col _ "__AF__" _ col_prefix
-                       errors = errors.$col
-                       heading = names.shift
-                       classmetadata = fclass_meta; # localize 
-       END;
-%]
-
diff --git a/ex/fancy_example/templates/custom/display_search_inputs b/ex/fancy_example/templates/custom/display_search_inputs
deleted file mode 100644 (file)
index 9985bfb..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-[%# 
-
-=head1 display_search_inputs
-
-This displays inputs for search page.  Override in individual class template
-directories as needed. 
-
-Vars it needs: 
-classmetadata-- the hash of inputs keyed on column names
-errors          -- hash of errors keyed on columns 
-=cut
-
-#%]
-
-[% IF errors.FATAL; "FATAL ERROR: "; errors.FATAL; "<br>"; END %]
-
-[%     USE this = Class(classmetadata.name);
-       SET srch_fields = classmetadata.search_columns || 
-                         classmetadata.columns; 
-       SET cgi         = classmetadata.cgi; 
-       SET delimiter = this.foreign_input_delimiter;
-       FOR field IN srch_fields;
-               NEXT IF !cgi.$field;
-               # Recursivly call this tmeplate if we have foreign field 
-        # (hash of foreign inputs should come with it) 
-               IF (  cgi.$field.keys ); 
-               fclass = this.related_class(request, field); 
-                       fclass_meta = this.get_classmetadata(fclass);
-                       fclass_meta.cgi = cgi.$field; 
-                       tbl   = fclass_meta.table;
-                       INCLUDE display_search_inputs
-                               col_prefix    = col _ delimiter _ col_prefix
-                               classmetadata = fclass_meta;
-                       NEXT;
-               END;
-
-       NEXT IF field == 'id' OR field == classmetadata.table _ 'id';
-       SET element = cgi.$field; 
-%]
-
-<label>
-               <span class="field">
-               [% 
-                       classmetadata.colnames.$field || field | ucfirst | replace('_',' '); %]
-               </span>
-               [%      IF element.tag == "select";
-                               # set the previous value 
-                               IF cgi_params.exists(field);
-                                       set_selected(element, cgi_params.$field);
-                               END;
-                                       
-                       END;
-            IF element.tag == "input";  # wipe out any default value
-                         old_val =  element.attr('value', '');
-               END;
-       
-
-               element.as_XML; 
-               %]
-</label>
-[% END; %]
-       
-
diff --git a/ex/fancy_example/templates/custom/edit b/ex/fancy_example/templates/custom/edit
deleted file mode 100644 (file)
index dae8c42..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-[%#
-
-=head1 edit
-
-This is the edit page. It edits the passed-in object, by displaying a
-form similar to L<addnew> but with the current values filled in.
-
-=cut
-
-#%]
-[% PROCESS macros %]
-[% INCLUDE header %]
-[% INCLUDE title %]
-
-[% IF request.action == 'edit' %]
-[% INCLUDE navbar %]
-[% END %]
-
-[% IF objects.size %]
-<div id="title">Edit a [% classmetadata.moniker %]</div>
-[% FOR item = objects; %]
-<form action="[% base %]/[% item.table %]/do_edit/[% item.id %]" method="post">
-<fieldset>
-<legend>Edit [% item.name %]</legend>
-[% FOR col = classmetadata.columns;
-    NEXT IF col == "id" OR col == classmetadata.table _ "_id";
-    '<label><span class="field">';
-    classmetadata.colnames.$col || col | ucfirst | replace('_',' '); ":</span>";
-    item.to_field(col).as_XML;
-    "</label>";
-    IF errors.$col; 
-       '<span class="error">'; errors.$col;'</span>';
-    END;
-    END %]
-    <input type="submit" name="edit" value="edit"/>
-    <input type="hidden" name="__form_id" value="[% request.make_random_id %]">
-    </fieldset></form>
-    
-    [% END %]
-[% ELSE %]
-
-<div id="addnew">
-<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
-<fieldset>
-<legend>Add a new [% classmetadata.moniker %]</legend>
-    [% FOR col = classmetadata.columns %]
-        [% NEXT IF col == "id" %]
-            <label><span class="field">[% classmetadata.colnames.$col %]</span>
-            [% 
-            SET elem = classmetadata.cgi.$col.clone;
-            IF request.action == 'do_edit';
-                IF elem.tag == "textarea";
-                    elem = elem.push_content(request.param(col));
-                ELSE;
-                    elem.attr("value", request.param(col));
-                END;
-            END;
-            elem.as_XML; %]
-           </label>
-        [% IF errors.$col %]
-           <span class="error">[% errors.$col | html  %]</span>
-        [% END %]
-
-    [% END; %]
-    <input type="submit" name="create" value="create" />
-    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
-</fieldset>
-</form>
-</div>
-
-[% END %]
-[% INCLUDE footer %]
diff --git a/ex/fancy_example/templates/custom/header b/ex/fancy_example/templates/custom/header
deleted file mode 100644 (file)
index c21fff7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-    <head>
-        <title>
-            [%
-              title || config.application_name ||
-                "A poorly configured Maypole application"
-            %]
-        </title>
-        <meta http-equiv="Content-Type" content="text/html; charset=[% request.document_encoding %]" />
-       <base href="[% config.uri_base%]"/>
-        <link title="Maypole" href="maypole.css" type="text/css" rel="stylesheet" />
-   </head>
-    <body>
-        <div class="content">
diff --git a/ex/fancy_example/templates/custom/maypole.css b/ex/fancy_example/templates/custom/maypole.css
deleted file mode 100644 (file)
index b13b4f1..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-html {
-    padding-right: 0px;
-    padding-left: 0px; 
-    padding-bottom: 0px; 
-    margin: 0px; 
-    padding-top: 0px
-}
-body {
-    font-family: sans-serif;
-    padding-right: 0px; 
-    padding-left: 0px; 
-    padding-bottom: 0px;
-    margin: 0px; padding-top: 0px;
-    background-color: #fff;
-}
-#frontpage_list {
-    position: absolute;
-    z-index: 5;
-    padding: 0px 100px 0px 0px;
-    margin:0 0.5%;     
-    margin-bottom:1em; 
-    margin-top: 1em;
-    background-color: #fff;
-}
-
-#frontpage_list a:hover {
-    background-color: #d0d8e4;
-}
-
-#frontpage_list ul {
-    list-style-type: square;
-}
-
-.content {
-    padding: 12px;
-    margin-top: 1px;  
-    margin-bottom:0px;
-    margin-left: 15px; 
-    margin-right: 15px;
-    border-color: #000000;
-    border-top: 0px;
-    border-bottom: 0px;
-    border-left: 1px;
-    border-right: 1px;
-}
-
-A { 
-    text-decoration: none; 
-    color:#225 
-}
-A:hover { 
-    text-decoration: underline; 
-    color:#222 
-}
-
-#title {
-    z-index: 6;
-    width: 100%;
-    height: 18px;
-    margin-top: 10px;
-    font-size: 90%;
-    border-bottom: 1px solid #ddf;
-    text-align: left;
-}
-
-#subtitle {
-    postion: absolute;
-    z-index: 6;
-    padding: 10px;
-    margin-top: 2em;
-    height: 18px;
-    text-align: left;
-    background-color: #fff;
-}
-
-input[type=text] {
-    height: 16px;
-    width: 136px;
-    font-family: sans-serif;
-    font-size: 11px;
-    color: #2E415A;
-    padding: 0px;
-    margin-bottom: 5px;
-}
-
-input[type=submit] {
-    height: 18px;
-    width: 60px;
-    font-family: sans-serif;
-    font-size: 11px;
-    border: 1px outset;
-    background-color: #fff;
-    padding: 0px 0px 2px 0px;
-    margin-bottom: 5px;
-}
-
-input:hover[type=submit] {
-    color: #fff;
-    background-color: #7d95b5;
-}
-
-textarea {
-    width: 136px;
-    font-family: sans-serif;
-    font-size: 11px;
-    color: #2E415A;
-    padding: 0px;
-    margin-bottom: 5px;
-}
-
-select {
-    height: 16px;
-    width: 140px;
-    font-family: sans-serif;
-    font-size: 12px;
-    color: #202020;
-    padding: 0px;
-    margin-bottom: 5px;
-}
-
-.deco1 {
-    font-size: 0px;
-    z-index:1;
-    border:0px;
-    border-style:solid;
-    border-color:#4d6d99;
-    background-color:#4d6d99;
-}
-
-.deco2 {
-    z-index:2;
-    border:0px;
-    border-style:solid;
-    border-color:#627ea5;
-    background-color:#627ea5;
-}
-
-
-.deco3 {
-    z-index:3;
-    border:0px;
-    border-style:solid;
-    border-color:#7d95b5;
-    background-color:#7d95b5;
-}
-                   
-.deco4 {
-    z-index:4;
-    border:0px;
-    border-style:solid;
-    border-color:#d0d8e4;
-    background-color:#d0d8e4;
-}
-                   
-
-table { 
-    border: 0px solid; 
-    background-color: #ffffff;
-}
-
-#matrix { width: 100%; }
-
-#matrix th {
-    background-color: #b5cadc;
-    border: 1px solid #778;
-    font: bold 12px Verdana, sans-serif;
-}
-
-#matrix #actionth {
-    width: 1px; 
-    padding: 0em 1em 0em 1em;
-}
-
-#matrix tr.alternate { background-color:#e3eaf0; }
-#matrix tr:hover { background-color: #b5cadc; }
-#matrix td { font: 12px Verdana, sans-serif; }
-
-#navlist {
-    padding: 3px 0;
-    margin-left: 0;
-    margin-top:3em;
-    border-bottom: 1px solid #778;
-    font: bold 12px Verdana, sans-serif;
-}
-
-#navlist li {
-    list-style: none;
-    margin: 0;
-    display: inline;
-}
-
-#navlist li a {
-    padding: 3px 0.5em;
-    margin-left: 3px;
-    border: 1px solid #778;
-    border-bottom: none;
-    background: #b5cadc;
-    text-decoration: none;
-}
-
-#navlist li a:link { color: #448; }
-#navlist li a:visited { color: #667; }
-
-#navlist li a:hover {
-    color: #000;
-    background: #eef;
-    border-top: 4px solid #7d95b5;
-    border-color: #227;
-}
-
-#navlist #active a {
-    background: white;
-    border-bottom: 1px solid white;
-    border-top: 4px solid;
-}
-
-td { font: 12px Verdana, sans-serif; }
-
-
-fieldset {
-    margin-top: 1em;
-    padding: 1em;
-    background-color: #f3f6f8;
-    font:80%/1 sans-serif;
-    border:1px solid #ddd;
-}
-
-legend {
-    padding: 0.2em 0.5em;
-    background-color: #fff;
-    border:1px solid #aaa;
-    font-size:90%;
-    text-align:right;
-}
-
-label {
-    display:block;
-}
-
-label.error {
-    display:block;
-       border-color: red;
-       border-width: 1px;
-}
-
-label .field {
-    float:left;
-    width:25%;
-    margin-right:0.5em;
-    padding-top:0.2em;
-    text-align:right;
-    font-weight:bold;
-}
-
-#vlist {
-    padding: 0 1px 1px;
-    margin-left: 0;
-    font: bold 12px Verdana, sans-serif;
-    background: gray;
-    width: 13em;
-}
-
-#vlist li {
-    list-style: none;
-    margin: 0;
-    border-top: 1px solid gray;
-    text-align: left;
-}
-
-#vlist li a {
-    display: block;
-    padding: 0.25em 0.5em 0.25em 0.75em;
-    border-left: 1em solid #7d95b5;
-    background: #d0d8e4;
-    text-decoration: none;
-}
-
-#vlist li a:hover { 
-    border-color: #227;
-}
-
-.view .field {
-    background-color: #f3f6f8;
-    border-left: 1px solid #7695b5;
-    border-top: 1px solid #7695b5;
-    padding: 1px 10px 0px 2px;
-}
-
-#addnew {
-    width: 50%;
-    float: left;
-}
-
-#search {
-    width: 50%;
-    float:right;
-}
-
-.error { color: #d00; }
-
-.action {
-    border: 1px outset #7d95b5;
-    style:block;
-}
-
-.action:hover {
-    color: #fff;
-    text-decoration: none;
-    background-color: #7d95b5;
-}
-
-.actionform {
-    display: inline;
-}
-
-.actionbutton {
-    height: 16px;
-    width: 40px;
-    font-family: sans-serif;
-    font-size: 10px;
-    border: 1px outset;
-    background-color: #fff;
-    margin-bottom: 0px;
-}
-
-.actionbutton:hover {
-    color: #fff;
-    background-color: #7d95b5;
-}
-
-.actions {
-    white-space: nowrap;
-}
-
-.field {
-    display:inline;
-}
-
-#login { width: 400px; }
-
-#login input[type=text] { width: 150px; }
-#login input[type=password] { width: 150px; }
-
-.pager {
-    font: 11px Arial, Helvetica, sans-serif;
-    text-align: center;
-    border: solid 1px #e2e2e2;
-    border-left: 0;
-    border-right: 0;
-    padding-top: 10px;
-    padding-bottom: 10px;
-    margin: 0px;
-    background-color: #f3f6f8;
-}
-
-.pager a {
-    padding: 2px 6px;
-    border: solid 1px #ddd;
-    background: #fff;
-    text-decoration: none;
-}
-
-.pager a:visited {
-    padding: 2px 6px;
-    border: solid 1px #ddd;
-    background: #fff;
-    text-decoration: none;
-}
-
-.pager .current-page {
-    padding: 2px 6px;
-    font-weight: bold;
-    vertical-align: top;
-}
-
-.pager a:hover {
-    color: #fff;
-    background: #7d95b5;
-    border-color: #036;
-    text-decoration: none;
-}
-
diff --git a/ex/fancy_example/templates/custom/metadata b/ex/fancy_example/templates/custom/metadata
deleted file mode 100644 (file)
index e15fb6a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<h3> Class::DBI meta info for [% classmetadata.name %] </h3> 
-[%
-   USE this = Class(classmetadata.name);
-   USE Dumper; Dumper.dump(this.meta_info);
-%]
diff --git a/ex/fancy_example/templates/custom/search_form b/ex/fancy_example/templates/custom/search_form
deleted file mode 100644 (file)
index 5d540fb..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<div id="search">
-<form method="get" action="[% base %]/[% classmetadata.table %]/search/">
-<fieldset>
-<legend>Search</legend>
-    [% INCLUDE display_search_inputs; %] 
-    <input type="submit" name="search" value="search"/>
-</fieldset>
-</form>
-</div>
diff --git a/ex/fancy_example/templates/factory/addnew b/ex/fancy_example/templates/factory/addnew
deleted file mode 100644 (file)
index 2334496..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-[%#
-
-=head1 addnew
-
-This is the interface to adding a new instance of an object. (or a new
-row in the database, if you want to look at it that way) It displays a
-form containing a list of HTML components for each of the columns in the
-table.
-
-=cut
-
-#%]
-
-<div id="addnew">
-<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
-    <fieldset>
-<legend>Add a new [% classmetadata.moniker %]</legend>
-    [% FOR col = classmetadata.columns %]
-        [% NEXT IF col == "id" %]
-            <label><span class="field">[% classmetadata.colnames.$col %]</span>
-            [% 
-            SET elem = classmetadata.cgi.$col.clone;
-            IF request.action == 'do_edit';
-                IF elem.tag == "textarea";
-                    elem = elem.push_content(request.param(col));
-                ELSE;
-                    elem.attr("value", request.param(col));
-                END;
-            END;
-            elem.as_XML; %]
-           </label>
-        [% IF errors.$col %]
-           <span class="error">[% errors.$col | html  %]</span>
-        [% END %]
-
-    [% END; %]
-    <input type="submit" name="create" value="create" />
-    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
-</fieldset>
-</form>
-</div>
diff --git a/ex/fancy_example/templates/factory/edit b/ex/fancy_example/templates/factory/edit
deleted file mode 100644 (file)
index cf88311..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-[%#
-
-=head1 edit
-
-This is the edit page. It edits the passed-in object, by displaying a
-form similar to L<addnew> but with the current values filled in.
-
-=cut
-
-#%]
-[% PROCESS macros %]
-[% INCLUDE header %]
-[% INCLUDE title %]
-
-[% IF request.action == 'edit' %]
-[% INCLUDE navbar %]
-[% END %]
-
-[% IF object %]
-<div id="title">Edit a [% classmetadata.moniker %]</div>
-<form action="[% base %]/[% item.table %]/do_edit/[% item.id %]" method="post">
-<fieldset>
-<legend>Edit [% object.name %]</legend>
-   [% FOR col = classmetadata.columns;
-    NEXT IF col == "id" OR col == classmetadata.table _ "_id";
-    '<label><span class="field">';
-    classmetadata.colnames.$col || col | ucfirst | replace('_',' '); ":</span>";
-    object.to_field(col).as_XML;
-    "</label>";
-    IF errors.$col; 
-       '<span class="error">'; errors.$col;'</span>';
-    END;
-    END %]
-    <input type="submit" name="edit" value="edit"/>
-    <input type="hidden" name="__form_id" value="[% request.make_random_id %]">
-    </fieldset></form>
-    
-[% ELSE %]
-
-<div id="addnew">
-<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
-<fieldset>
-<legend>Add a new [% classmetadata.moniker %]</legend>
-    [% FOR col = classmetadata.columns %]
-        [% NEXT IF col == "id" %]
-            <label><span class="field">[% classmetadata.colnames.$col %]</span>
-            [% 
-            SET elem = classmetadata.cgi.$col.clone;
-            IF request.action == 'do_edit';
-                IF elem.tag == "textarea";
-                    elem = elem.push_content(request.param(col));
-                ELSE;
-                    elem.attr("value", request.param(col));
-                END;
-            END;
-            elem.as_XML; %]
-           </label>
-        [% IF errors.$col %]
-           <span class="error">[% errors.$col | html  %]</span>
-        [% END %]
-
-    [% END; %]
-    <input type="submit" name="create" value="create" />
-    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
-</fieldset>
-</form>
-</div>
-
-[% END %]
-[% INCLUDE footer %]
diff --git a/ex/fancy_example/templates/factory/footer b/ex/fancy_example/templates/factory/footer
deleted file mode 100644 (file)
index 1b8ae55..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-       </div>
-    </body>
-</html>
diff --git a/ex/fancy_example/templates/factory/frontpage b/ex/fancy_example/templates/factory/frontpage
deleted file mode 100644 (file)
index ac47269..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-[%#
-
-=head1 frontpage
-
-This is the frontpage for your Maypole application.
-It shows a list of all tables it is allowed to display.
-
-=cut
-
-#%]
-[% INCLUDE header %]
-<div id="title">
-    [% config.application_name || "A poorly configured Maypole application" %]
-</div>
-<div id="frontpage_list">
-<ul>
-[% FOR table = config.display_tables %]
-    <li>
-        <a href="[% base %]/[%table%]/list">List by [%table %]</a>
-    </li>      
-[% END %]
-</ul>
-</div>
-
-[% INCLUDE maypole %]
-
-[% INCLUDE footer %]
diff --git a/ex/fancy_example/templates/factory/header b/ex/fancy_example/templates/factory/header
deleted file mode 100644 (file)
index ba0b190..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-    <head>
-        <title>
-            [%
-              title || config.application_name ||
-                "A poorly configured Maypole application"
-            %]
-        </title>
-        <meta http-equiv="Content-Type" content="text/html; charset=[% request.document_encoding %]" />
-       <base href="[% config.uri_base%]"/>
-        <link title="Maypole" href="[% config.uri_base %]/maypole.css" type="text/css" rel="stylesheet" />
-   </head>
-    <body>
-        <div class="content">
diff --git a/ex/fancy_example/templates/factory/list b/ex/fancy_example/templates/factory/list
deleted file mode 100644 (file)
index 9abbc01..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-[% PROCESS macros %]
-[% INCLUDE header %]
-[% INCLUDE title %]
-[% IF search %]
-    <div id="title">Search results</div>
-[% ELSE %]
-    <div id="title">Listing of all [% classmetadata.plural %]</div>
-[% END %]
-[% INCLUDE navbar %]
-<div class="list">
-    <table id="matrix">
-        <tr>
-            [% FOR col = classmetadata.list_columns.list;
-                NEXT IF col == "id" OR col == classmetadata.table _ "_id";
-                "<th>"; 
-                SET additional = "?order=" _ col;
-                SET additional = additional _ "&page=" _ pager.current_page
-                    IF pager;
-                SET additional = additional _ "&o2=desc" 
-                IF col == request.params.order and request.params.o2 != "desc";
-                SET action = "list";
-                FOR name = classmetadata.columns.list;
-                  IF request.query.$name;
-                    SET additional =
-                        additional  _ "&" _ name _ "=" _
-                        request.params.$name;
-                    SET action = "search";
-                  END;
-                END;
-               USE model_obj = Class request.model_class;
-               IF model_obj.find_column(col);
-                  link(classmetadata.table, action, additional,
-                    classmetadata.colnames.$col);
-                  IF col == request.params.order;
-                    IF request.params.o2 != "desc";
-                        "&darr;";
-                    ELSE;
-                        "&uarr;";
-                    END;
-                  END;
-               ELSE;
-                 classmetadata.colnames.$col || col FILTER ucfirst;
-               END;
-                "</th>";
-            END %]
-           <th id="actionth">Actions</th>
-        </tr>
-        [%  SET count = 0;
-        FOR item = objects;
-            SET count = count + 1;
-            "<tr";
-            ' class="alternate"' IF count % 2;
-            ">";
-            display_line(item);
-            "</tr>";
-        END %]
-    </table>
-
-[% INCLUDE pager %]
-[% INCLUDE addnew %]
-[% INCLUDE search_form %]
-</div>
-[% INCLUDE footer %]
diff --git a/ex/fancy_example/templates/factory/login b/ex/fancy_example/templates/factory/login
deleted file mode 100644 (file)
index af08e5b..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-[% PROCESS macros %]
-[% INCLUDE header %]
-[% INCLUDE title %]
-[% user_field = config.auth.user_field || "user" %]
-
-    <div id="title">You need to log in</div>
-
-    <div id="login">
-    [% IF login_error %]
-        <div class="error"> [% login_error | html %] </div>
-    [% END %]
-    <form method="post" action="[% base %]/[% request.path %]">
-    <fieldset>
-    <legend>Login</legend>
-        <label>
-            <span class="field">Username:</span>
-           <input name="[% user_field %]" type="text" value="[% cgi_params.$user_field | html %]" />
-        </label>
-       <label>
-           <span class="field">Password:</span>
-                   <input name="password" type="password" value="[% cgi_params.passwrd | html %]"/>
-       </label>        
-        <input type="submit" name="login" value="Submit"/>
-    </fieldset>
-    </form>
-    </div>
-
diff --git a/ex/fancy_example/templates/factory/macros b/ex/fancy_example/templates/factory/macros
deleted file mode 100644 (file)
index fc75d09..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-[%#
-
-=head1 MACROS
-
-These are some default macros which are used by various templates in the
-system.
-
-=head2 link
-
-This creates an <A HREF="..."> to a command in the Apache::MVC system by
-catenating the base URL, table, command, and any arguments.
-
-#%]
-[%
-MACRO link(table, command, additional, label) BLOCK;
-    SET lnk = base _ "/" _ table _ "/" _ command _ "/" _ additional;
-    lnk = lnk | uri | html;
-    '<a href="' _ lnk _ '">';
-    label | html;
-    "</a>";
-END;
-%]
-
-[%#
-
-=head2 maybe_link_view
-
-C<maybe_link_view> takes something returned from the database - either
-some ordinary data, or an object in a related class expanded by a
-has-a relationship. If it is an object, it constructs a link to the view
-command for that object. Otherwise, it just displays the data.
-
-#%]
-
-[%
-MACRO maybe_link_view(object) BLOCK;
-    IF object.isa('Maypole::Model::Base');
-        link(object.table, "view", object.id.join('/'), object);
-    ELSE;
-        object | html ;
-    END;
-END;
-%]
-
-[%#
-
-=head2 display_line
-
-C<display_line> is used in the list template to display a row from the
-database, by iterating over the columns and displaying the data for each
-column. It misses out the C<id> column by default, and magically
-URLifies columns called C<url>. This may be considered too much magic
-for some.
-
-#%]
-[% MACRO display_line(item) BLOCK;
-    FOR col = classmetadata.list_columns;
-       NEXT IF col == "id" OR col == classmetadata.table _ "_id";
-       col_obj = item.find_column(col);
-        "<td>";
-        IF col == "url" AND item.url;
-            '<a href="'; item.url | html ; '"> '; item.url; '</a>';
-        ELSIF col == classmetadata.stringify_column;
-            maybe_link_view(item);
-               ELSIF col_obj; # its a real column
-            accessor = item.accessor_name_for(col_obj) ||
-                                  item.accessor_name(col_obj); # deprecated in cdbi
-            maybe_link_view(item.$accessor);
-        ELSE; 
-            item.$col;
-        END;
-
-        "</td>";
-    END;
-    '<td class="actions">';
-    button(item, "edit");
-    button(item, "delete");
-    "</td>";
-END %]
-[%#
-
-=head2 button
-
-This is a generic button, which performs an action on an object.
-
-=cut
-
-#%]
-[% MACRO button(obj, action) BLOCK; %]
-[% IF obj.is_public(action) %]
-<form class="actionform" action="[% base %]/[% obj.table %]/[% action %]/[% obj.id.join('/') %]" method="post">
-<div class="field"><input class="actionbutton" type="submit" value="[% action %]" /></div></form>
-[% END %]
-[% END %]
-[%#
-
-=head2 view_related
-
-This takes an object, and looks up the C<related_accessors>; this should
-give a list of accessors that can be called to get a list of related
-objects. It then displays a title for that accessor, (i.e. "Beers" for a
-brewery) calls the accesor, and displays a list of the results. 
-
-=cut
-
-#%]
-[% 
-MACRO view_related(object) BLOCK;
-    FOR accessor = classmetadata.related_accessors.list;
-        "<div id=\"subtitle\">"; accessor | ucfirst; "</div>\n";
-        "<ul id=\"vlist\">";
-        FOR thing = object.$accessor;
-            "<li>"; maybe_link_view(thing); "</li>\n";
-        END;
-        "</ul>";
-    END; 
-END;
-
-MACRO test_xxxx(myblock) BLOCK;
-    FOR col = classmetadata.columns;
-        NEXT IF col == "id";
-        myblock;
-    END;
-END;
-%]
-[%#
-
-=head2 view_item
-
-This takes an object and and displays its properties in a table. 
-
-=cut
-
-#%]
-[% MACRO view_item(item) BLOCK; %]
-    [% SET string = classmetadata.stringify_column %]
-    <div id="title"> [% item.$string | html %]</div>
-    [% INCLUDE navbar %]
-    <table class="view">
-        <tr>
-            <td class="field">[% classmetadata.colnames.$string  %]</td>
-            <td>[% item.$string | html %]</td>
-        </tr>
-        [% FOR col = classmetadata.columns.list;
-            NEXT IF col == "id" OR col == string OR col == classmetadata.table _ "_id";;
-            NEXT UNLESS item.$col;
-        %]
-[%# 
-
-=for doc
-
-It gets the displayable form of a column's name from the hash returned
-from the C<column_names> method:
-
-#%]
-            <tr>
-                <td class="field">[% classmetadata.colnames.$col || 
-                     col | ucfirst | replace('_',' '); %]</td>
-                <td>
-                    [% IF col == "url" && item.url;  # Possibly too much magic.
-                        '<a href="'; item.url | html ; '"> '; item.url; '</a>';
-                                       ELSIF item.$col.size > 1; # has_many column
-                                               FOR thing IN item.$col; 
-                                                       maybe_link_view(thing);",  ";
-                                                END;
-
-                    ELSE;
-                        maybe_link_view(item.$col); 
-                    END; %]
-[%#
-
-This tests whether or not the returned value is an object, and if so,
-creates a link to a page viewing that object; if not, it just displays
-the text as normal. The object is linked using its stringified name;
-by default this calls the C<name> method, or returns the object's ID
-if there is no C<name> method or other stringification method defined.
-
-=cut
-
-#%] 
-                </td>
-            </tr>
-        [% END; %]
-    </table>
-[% END %]
diff --git a/ex/fancy_example/templates/factory/maypole b/ex/fancy_example/templates/factory/maypole
deleted file mode 100644 (file)
index 7ab2744..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- boxes -->
-<div style='position:absolute;top:220px;left:130px;border-bottom-width:260px;border-right-width:370px;' class='deco1'>&nbsp;</div>
-<div style='position:absolute;top:260px;left:190px;border-bottom-width:170px;border-right-width:530px;' class='deco2'>&nbsp;</div>
-<div style='position:absolute;top:240px;left:220px;border-bottom-width:340px;border-right-width:440px;' class='deco4'>&nbsp;</div>
-<div style='position:absolute;top:160px;left:330px;border-bottom-width:160px;border-right-width:280px;' class='deco1'>&nbsp;</div>
-<div style='position:absolute;top:190px;left:290px;border-bottom-width:430px;border-right-width:130px;' class='deco2'>&nbsp;</div>
-<!-- end of boxes -->
diff --git a/ex/fancy_example/templates/factory/maypole.css b/ex/fancy_example/templates/factory/maypole.css
deleted file mode 100644 (file)
index d63be55..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-html {
-    padding-right: 0px;
-    padding-left: 0px; 
-    padding-bottom: 0px; 
-    margin: 0px; 
-    padding-top: 0px
-}
-body {
-    font-family: sans-serif;
-    padding-right: 0px; 
-    padding-left: 0px; 
-    padding-bottom: 0px;
-    margin: 0px; padding-top: 0px;
-    background-color: #fff;
-}
-#frontpage_list {
-    position: absolute;
-    z-index: 5;
-    padding: 0px 100px 0px 0px;
-    margin:0 0.5%;     
-    margin-bottom:1em; 
-    margin-top: 1em;
-    background-color: #fff;
-}
-
-#frontpage_list a:hover {
-    background-color: #d0d8e4;
-}
-
-#frontpage_list ul {
-    list-style-type: square;
-}
-
-.content {
-    padding: 12px;
-    margin-top: 1px;  
-    margin-bottom:0px;
-    margin-left: 15px; 
-    margin-right: 15px;
-    border-color: #000000;
-    border-top: 0px;
-    border-bottom: 0px;
-    border-left: 1px;
-    border-right: 1px;
-}
-
-A { 
-    text-decoration: none; 
-    color:#225 
-}
-A:hover { 
-    text-decoration: underline; 
-    color:#222 
-}
-
-#title {
-    z-index: 6;
-    width: 100%;
-    height: 18px;
-    margin-top: 10px;
-    font-size: 90%;
-    border-bottom: 1px solid #ddf;
-    text-align: left;
-}
-
-#subtitle {
-    postion: absolute;
-    z-index: 6;
-    padding: 10px;
-    margin-top: 2em;
-    height: 18px;
-    text-align: left;
-    background-color: #fff;
-}
-
-input[type=text] {
-    height: 16px;
-    width: 136px;
-    font-family: sans-serif;
-    font-size: 11px;
-    color: #2E415A;
-    padding: 0px;
-    margin-bottom: 5px;
-}
-
-input[type=submit] {
-    height: 18px;
-    width: 60px;
-    font-family: sans-serif;
-    font-size: 11px;
-    border: 1px outset;
-    background-color: #fff;
-    padding: 0px 0px 2px 0px;
-    margin-bottom: 5px;
-}
-
-input:hover[type=submit] {
-    color: #fff;
-    background-color: #7d95b5;
-}
-
-textarea {
-    width: 136px;
-    font-family: sans-serif;
-    font-size: 11px;
-    color: #2E415A;
-    padding: 0px;
-    margin-bottom: 5px;
-}
-
-select {
-    height: 16px;
-    width: 140px;
-    font-family: sans-serif;
-    font-size: 12px;
-    color: #202020;
-    padding: 0px;
-    margin-bottom: 5px;
-}
-
-.deco1 {
-    font-size: 0px;
-    z-index:1;
-    border:0px;
-    border-style:solid;
-    border-color:#4d6d99;
-    background-color:#4d6d99;
-}
-
-.deco2 {
-    z-index:2;
-    border:0px;
-    border-style:solid;
-    border-color:#627ea5;
-    background-color:#627ea5;
-}
-
-
-.deco3 {
-    z-index:3;
-    border:0px;
-    border-style:solid;
-    border-color:#7d95b5;
-    background-color:#7d95b5;
-}
-                   
-.deco4 {
-    z-index:4;
-    border:0px;
-    border-style:solid;
-    border-color:#d0d8e4;
-    background-color:#d0d8e4;
-}
-                   
-
-table { 
-    border: 0px solid; 
-    background-color: #ffffff;
-}
-
-#matrix { width: 100%; }
-
-#matrix th {
-    background-color: #b5cadc;
-    border: 1px solid #778;
-    font: bold 12px Verdana, sans-serif;
-}
-
-#matrix #actionth {
-    width: 1px; 
-    padding: 0em 1em 0em 1em;
-}
-
-#matrix tr.alternate { background-color:#e3eaf0; }
-#matrix tr:hover { background-color: #b5cadc; }
-#matrix td { font: 12px Verdana, sans-serif; }
-
-#navlist {
-    padding: 3px 0;
-    margin-left: 0;
-    margin-top:3em;
-    border-bottom: 1px solid #778;
-    font: bold 12px Verdana, sans-serif;
-}
-
-#navlist li {
-    list-style: none;
-    margin: 0;
-    display: inline;
-}
-
-#navlist li a {
-    padding: 3px 0.5em;
-    margin-left: 3px;
-    border: 1px solid #778;
-    border-bottom: none;
-    background: #b5cadc;
-    text-decoration: none;
-}
-
-#navlist li a:link { color: #448; }
-#navlist li a:visited { color: #667; }
-
-#navlist li a:hover {
-    color: #000;
-    background: #eef;
-    border-top: 4px solid #7d95b5;
-    border-color: #227;
-}
-
-#navlist #active a {
-    background: white;
-    border-bottom: 1px solid white;
-    border-top: 4px solid;
-}
-
-td { font: 12px Verdana, sans-serif; }
-
-
-fieldset {
-    margin-top: 1em;
-    padding: 1em;
-    background-color: #f3f6f8;
-    font:80%/1 sans-serif;
-    border:1px solid #ddd;
-}
-
-legend {
-    padding: 0.2em 0.5em;
-    background-color: #fff;
-    border:1px solid #aaa;
-    font-size:90%;
-    text-align:right;
-}
-
-label {
-    display:block;
-}
-
-label.error {
-       border-color: red;
-       border-width: 1px;
-}
-
-label .field {
-    float:left;
-    width:25%;
-    margin-right:0.5em;
-    padding-top:0.2em;
-    text-align:right;
-    font-weight:bold;
-}
-
-#vlist {
-    padding: 0 1px 1px;
-    margin-left: 0;
-    font: bold 12px Verdana, sans-serif;
-    background: gray;
-    width: 13em;
-}
-
-#vlist li {
-    list-style: none;
-    margin: 0;
-    border-top: 1px solid gray;
-    text-align: left;
-}
-
-#vlist li a {
-    display: block;
-    padding: 0.25em 0.5em 0.25em 0.75em;
-    border-left: 1em solid #7d95b5;
-    background: #d0d8e4;
-    text-decoration: none;
-}
-
-#vlist li a:hover { 
-    border-color: #227;
-}
-
-.view .field {
-    background-color: #f3f6f8;
-    border-left: 1px solid #7695b5;
-    border-top: 1px solid #7695b5;
-    padding: 1px 10px 0px 2px;
-}
-
-#addnew {
-    width: 50%;
-    float: left;
-}
-
-#search {
-    width: 50%;
-    float:right;
-}
-
-.error { color: #d00; }
-
-.action {
-    border: 1px outset #7d95b5;
-    style:block;
-}
-
-.action:hover {
-    color: #fff;
-    text-decoration: none;
-    background-color: #7d95b5;
-}
-
-.actionform {
-    display: inline;
-}
-
-.actionbutton {
-    height: 16px;
-    width: 40px;
-    font-family: sans-serif;
-    font-size: 10px;
-    border: 1px outset;
-    background-color: #fff;
-    margin-bottom: 0px;
-}
-
-.actionbutton:hover {
-    color: #fff;
-    background-color: #7d95b5;
-}
-
-.actions {
-    white-space: nowrap;
-}
-
-.field {
-    display:inline;
-}
-
-#login { width: 400px; }
-
-#login input[type=text] { width: 150px; }
-#login input[type=password] { width: 150px; }
-
-.pager {
-    font: 11px Arial, Helvetica, sans-serif;
-    text-align: center;
-    border: solid 1px #e2e2e2;
-    border-left: 0;
-    border-right: 0;
-    padding-top: 10px;
-    padding-bottom: 10px;
-    margin: 0px;
-    background-color: #f3f6f8;
-}
-
-.pager a {
-    padding: 2px 6px;
-    border: solid 1px #ddd;
-    background: #fff;
-    text-decoration: none;
-}
-
-.pager a:visited {
-    padding: 2px 6px;
-    border: solid 1px #ddd;
-    background: #fff;
-    text-decoration: none;
-}
-
-.pager .current-page {
-    padding: 2px 6px;
-    font-weight: bold;
-    vertical-align: top;
-}
-
-.pager a:hover {
-    color: #fff;
-    background: #7d95b5;
-    border-color: #036;
-    text-decoration: none;
-}
-
diff --git a/ex/fancy_example/templates/factory/navbar b/ex/fancy_example/templates/factory/navbar
deleted file mode 100644 (file)
index 0c8b168..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-[%#
-
-=head1 navbar
-
-This is a navigation bar to go across the page. (Or down the side, or
-whatetver you want to do with it.) It displays all the tables which are
-accessible, with a link to the list page for each one.
-
-#%]
-[% PROCESS macros %]
-<div id="navcontainer">
-<ul id="navlist">
-[%
-    FOR table = config.display_tables;
-        '<li '; 'id="active"' IF table == classmetadata.table; '>';
-        # Hack
-        link(table, "list", "", table);
-        '</li>';
-    END;
-%]
-</ul>
-</div> 
diff --git a/ex/fancy_example/templates/factory/pager b/ex/fancy_example/templates/factory/pager
deleted file mode 100644 (file)
index 78c89fd..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-[%#
-
-=head1 pager
-
-This controls the pager display at the bottom (by default) of the list
-and search views. It expects a C<pager> template argument which responds
-to the L<Data::Page> interface.
-
-#%]
-[%
-IF pager AND pager.first_page != pager.last_page;
-%]
-<p class="pager">Pages: 
-[%
-    UNLESS pager_action;
-       SET pager_action = request.action;
-    END;
-   
-    SET begin_page = pager.current_page - 10;
-    IF begin_page < 1;
-        SET begin_page = pager.first_page;
-    END;
-    SET end_page = pager.current_page + 10;
-    IF pager.last_page < end_page;
-        SET end_page = pager.last_page;
-    END;
-     FOREACH num = [begin_page .. end_page];
-          IF num == pager.current_page;
-            "<span class='current-page'>"; num; "</span>";
-          ELSE;
-            SET label = num;
-            SET args = "?page=" _ num;
-           SET args = args _ "&order=" _ request.params.order
-             IF request.params.order;
-           SET args = args _ "&amp;o2=desc"
-             IF request.params.o2 == "desc";
-            FOR col = classmetadata.columns.list;
-              IF request.params.$col;
-                SET args = args _ "&" _ col _ "=" _ request.params.$col;
-                SET action = "search";
-              END;
-            END;
-            link(classmetadata.table, pager_action, args, label);
-          END;
-     END;
-%]
-</p>
-[% END %]
diff --git a/ex/fancy_example/templates/factory/search_form b/ex/fancy_example/templates/factory/search_form
deleted file mode 100644 (file)
index d10101e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<div id="search">
-<form method="get" action="[% base %]/[% classmetadata.moniker %]/search/">
-<fieldset>
-<legend>Search</legend>
-        [% FOR col = classmetadata.columns;
-            NEXT IF col == "id" OR col == classmetadata.table _ "_id";
-         %]
-           <label>
-                <span class="field">[% classmetadata.colnames.$col; %]</span>
-                    [% SET element = classmetadata.cgi.$col;
-                    IF element.tag == "select";
-                        USE element_maker = Class("HTML::Element");
-                        SET element = element.unshift_content(
-                            element_maker.new("option", value," "));
-                    END;
-                   element.as_XML; %]
-                  </label>
-        [% END; %]
-    <input type="submit" name="search" value="search"/>
-    </fieldset>
-</form>
-</div>
diff --git a/ex/fancy_example/templates/factory/search_form_recursive b/ex/fancy_example/templates/factory/search_form_recursive
deleted file mode 100644 (file)
index 5d540fb..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<div id="search">
-<form method="get" action="[% base %]/[% classmetadata.table %]/search/">
-<fieldset>
-<legend>Search</legend>
-    [% INCLUDE display_search_inputs; %] 
-    <input type="submit" name="search" value="search"/>
-</fieldset>
-</form>
-</div>
diff --git a/ex/fancy_example/templates/factory/title b/ex/fancy_example/templates/factory/title
deleted file mode 100644 (file)
index 401f0a3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-    <a href="[% base %]/frontpage">[% config.application_name %]</a>
diff --git a/ex/fancy_example/templates/factory/view b/ex/fancy_example/templates/factory/view
deleted file mode 100644 (file)
index 9f06086..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-[%#
-
-=for doc
-
-The C<view> template takes some objects (usually just one) from
-C<objects> and displays the object's properties in a table. 
-
-=cut
-
-#%]
-[% PROCESS macros %]
-[% INCLUDE header %]
-[% view_item(object); %]
-[%#
-
-=for doc
-
-The C<view> template also displays a list of other objects related to the first
-one via C<has_many> style relationships; this is done by calling the
-C<related_accessors> method - see L<Model/related_accessors> - to return
-a list of has-many accessors. Next it calls each of those accessors, and
-displays the results in a table.
-
-#%]
-    <br /><a href="[%base%]/[%object.table%]/list">Back to listing</a>
-[% view_related(object); %]
-    
-[%
-    button(object, "edit");
-    button(object, "delete");
-%]
-[% INCLUDE footer %]
diff --git a/examples/BeerDB.pm b/examples/BeerDB.pm
new file mode 100644 (file)
index 0000000..e0b2894
--- /dev/null
@@ -0,0 +1,66 @@
+package BeerDB;
+use Maypole::Application;
+use Class::DBI::Loader::Relationship;
+
+sub debug { $ENV{BEERDB_DEBUG} || 0 }
+# This is the sample application.  Change this to the path to your
+# database. (or use mysql or something)
+use constant DBI_DRIVER => 'SQLite';
+use constant DATASOURCE => $ENV{BEERDB_DATASOURCE} || 't/beerdb.db';
+
+
+BEGIN {
+    my $dbi_driver = DBI_DRIVER;
+    if ($dbi_driver =~ /^SQLite/) {
+        die sprintf "SQLite datasource '%s' not found, correct the path or "
+            . "recreate the database by running Makefile.PL", DATASOURCE
+            unless -e DATASOURCE;
+        eval "require DBD::SQLite";
+        if ($@) {
+            eval "require DBD::SQLite2" and $dbi_driver = 'SQLite2';
+        }
+    }
+    BeerDB->setup(join ':', "dbi", $dbi_driver, DATASOURCE);
+}
+
+# Give it a name.
+BeerDB->config->application_name('The Beer Database');
+
+# Change this to the root of the web site for your maypole application.
+BeerDB->config->uri_base( $ENV{BEERDB_BASE} || "http://localhost/beerdb/" );
+
+# Change this to the htdoc root for your maypole application.
+
+my @root=  ('t/templates'); 
+push @root,$ENV{BEERDB_TEMPLATE_ROOT} if ($ENV{BEERDB_TEMPLATE_ROOT});
+BeerDB->config->template_root( [@root] ); 
+# Specify the rows per page in search results, lists, etc : 10 is a nice round number
+BeerDB->config->rows_per_page(10);
+
+# Handpumps should not show up.
+BeerDB->config->display_tables([qw[beer brewery pub style]]);
+BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
+BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
+BeerDB::Beer->untaint_columns(
+    printable => [qw/abv name price notes url/],
+    integer => [qw/style brewery score/],
+    date =>[ qw/tasted/],
+);
+BeerDB::Pub->untaint_columns(printable => [qw/name notes url/]);
+
+# Required Fields
+BeerDB->config->{brewery}{required_cols} = [qw/name/];
+BeerDB->config->{style}{required_cols} = [qw/name/];
+BeerDB->config->{beer}{required_cols} = [qw/brewery name price/];
+BeerDB->config->{pub}{required_cols} = [qw/name/];
+
+BeerDB->config->{loader}->relationship($_) for (
+    "a brewery produces beers",
+    "a style defines beers",
+    "a pub has beers on handpumps");
+
+# For testing classmetadata
+sub BeerDB::Beer::classdata :Exported {};
+sub BeerDB::Beer::list_columns  { return qw/score name price style brewery url/};
+
+1;
diff --git a/examples/BeerDB/Base.pm b/examples/BeerDB/Base.pm
new file mode 100644 (file)
index 0000000..75ed338
--- /dev/null
@@ -0,0 +1,7 @@
+package BeerDB::Base;
+use strict;
+use warnings;
+
+sub floob {}
+
+1;
diff --git a/examples/BeerDB/Beer.pm b/examples/BeerDB/Beer.pm
new file mode 100644 (file)
index 0000000..d7de346
--- /dev/null
@@ -0,0 +1,10 @@
+package BeerDB::Beer;
+use strict;
+use warnings;
+
+# do this to test we get the expected @ISA after setup_model()
+use base 'BeerDB::Base';
+
+sub fooey : Exported {}
+
+1;
diff --git a/examples/beerdb.sql b/examples/beerdb.sql
new file mode 100644 (file)
index 0000000..0c6a0df
--- /dev/null
@@ -0,0 +1,38 @@
+CREATE TABLE style (
+    id integer primary key auto_increment,
+    name varchar(60),
+    notes text
+);
+
+CREATE TABLE pub (
+    id integer primary key auto_increment,
+    name varchar(60),
+    url varchar(120),
+    notes text
+);
+
+CREATE TABLE handpump (
+    id integer primary key auto_increment,
+    beer integer,
+    pub integer
+);
+
+CREATE TABLE beer (
+    id integer primary key auto_increment,
+    brewery integer,
+    style integer,
+    name varchar(30),
+    url varchar(120),
+    score integer(2),
+    price varchar(12),
+    abv varchar(10),
+    notes text,
+       tasted date
+);
+
+CREATE TABLE brewery (
+    id integer  primary key auto_increment,
+    name varchar(30),
+    url varchar(50),
+    notes text
+);
diff --git a/examples/fancy_example/BeerDB.pm b/examples/fancy_example/BeerDB.pm
new file mode 100644 (file)
index 0000000..cb72574
--- /dev/null
@@ -0,0 +1,78 @@
+package BeerDB;
+use Maypole::Application;
+use Class::DBI::Loader::Relationship;
+
+sub debug { $ENV{BEERDB_DEBUG} || 0 }
+# This is the sample application.  Change this to the path to your
+# database. (or use mysql or something)
+use constant DBI_DRIVER => 'SQLite';
+use constant DATASOURCE => '/home/peter/Desktop/maypolebeer/beerdb'; 
+
+BeerDB->config->model('BeerDB::Base'); 
+
+BeerDB->setup("dbi:mysql:beerdb",'root', '');
+
+# Give it a name.
+BeerDB->config->application_name('The Beer Database');
+
+# Change this to the root of the web site for your maypole application.
+BeerDB->config->uri_base( $ENV{BEERDB_BASE} || "http://localhost/beerdb/" );
+
+# Change this to the htdoc root for your maypole application.
+
+my @root=  ('/home/peter/Desktop/maypolebeer/templates'); 
+push @root,$ENV{BEERDB_TEMPLATE_ROOT} if ($ENV{BEERDB_TEMPLATE_ROOT});
+BeerDB->config->template_root( [@root] ); 
+# Specify the rows per page in search results, lists, etc : 10 is a nice round number
+BeerDB->config->rows_per_page(10);
+
+# Let TT templates recursively include  themselves
+BeerDB->config->{view_options} = { RECURSION => 1, };
+
+# Handpumps should not show up.
+BeerDB->config->display_tables([qw[beer brewery pub style drinker pint person]]);
+# Access handpumps if want
+BeerDB->config->ok_tables([ @{BeerDB->config->display_tables}, qw[handpump]]);
+
+BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
+BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
+BeerDB::Beer->untaint_columns(
+    printable => [qw/abv name price notes/],
+    integer => [qw/style brewery score/],
+    date =>[ qw/tasted/],
+);
+BeerDB::Pub->untaint_columns(printable => [qw/name notes url/]);
+BeerDB::Drinker->untaint_columns( printable => [qw/handle created/] );
+BeerDB::Pint->untaint_columns( printable => [qw/date_and_time/]);
+
+
+# Required Fields
+BeerDB->config->{brewery}{required_cols} = [qw/name url/];
+BeerDB->config->{style}{required_cols} = [qw/name/];
+BeerDB->config->{beer}{required_cols} = [qw/brewery name price/];
+BeerDB->config->{pub}{required_cols} = [qw/name/];
+BeerDB->config->{drinker}{required_cols} = [qw/handle person/];
+BeerDB->config->{pint}{required_cols} = [qw/drinker handpump/]; 
+BeerDB->config->{person}{required_cols} = [qw/first_name sur_name dob email/];
+
+# Columns to display 
+sub BeerDB::Handpump::display_columns { qw/pub beer/ }
+
+BeerDB->config->{loader}->relationship($_) for (
+    "a brewery produces beers",
+    "a style defines beers",
+    "a pub has beers on handpumps",
+    "a handpump defines pints",
+    "a drinker drinks pints",);
+
+# For testing classmetadata
+#sub BeerDB::Beer::classdata :Exported {};
+sub BeerDB::Beer::list_columns  { return qw/score name price style brewery/};
+
+sub BeerDB::Handpump::stringify_self { 
+       my $self = shift; 
+       return $self->beer . " @ " . $self->pub;
+}
+
+
+1;
diff --git a/examples/fancy_example/BeerDB/Base.pm b/examples/fancy_example/BeerDB/Base.pm
new file mode 100644 (file)
index 0000000..aaafce1
--- /dev/null
@@ -0,0 +1,51 @@
+package BeerDB::Base;
+use base qw/Maypole::Model::CDBI/;
+use strict;
+use warnings;
+use Data::Dumper;
+
+# Overide list to add display_columns to cgi  
+# Perhaps do this in AsForm?
+sub list : Exported {
+       use Data::Dumper;
+       my ($self, $r) = @_;
+       $self->SUPER::list($r);
+       my %cols =  map { $_ => 1 } $self->columns, $self->display_columns;
+       my @cols = keys %cols;
+       $r->template_args->{classmetadata}{cgi} = { $self->to_cgi(@cols) }; 
+}
+
+# Override view to make inputs and process form to add to related 
+sub view : Exported {
+    my ($self, $r, $obj) = @_;
+    $self->_croak( "Object method only") unless $obj;
+
+    if ($r->params->{submit}) {
+        my @related  = $obj->add_to_from_cgi($r, { required => [$self->related ]});
+        if (my $errs = $obj->cgi_update_errors) {
+            $r->template_args->{errors} = $errs;
+        }
+    }
+
+    # Inputs to add to related on the view page
+       # Now done on the view template 
+       # my %cgi = $self->to_cgi($self->related);
+       #$r->template_args->{classmetadata}{cgi} =  \%cgi ;
+}
+
+
+# Template switcheroo bug bit me -- was seeing view page but the view action was never 
+# being executed after an edit.
+sub do_edit : Exported {
+       my ($self, $r) = (shift, shift);
+       $self->SUPER::do_edit($r, @_);
+       if (my $obj = $r->object) {
+               my $url = $r->config->uri_base . "/" . $r->table . "/view/" . $obj->id;
+               $r->redirect_request(url => $url);
+       }
+}
+
+sub metadata: Exported {}
+       
+
+1;
diff --git a/examples/fancy_example/BeerDB/Beer.pm b/examples/fancy_example/BeerDB/Beer.pm
new file mode 100644 (file)
index 0000000..d7de346
--- /dev/null
@@ -0,0 +1,10 @@
+package BeerDB::Beer;
+use strict;
+use warnings;
+
+# do this to test we get the expected @ISA after setup_model()
+use base 'BeerDB::Base';
+
+sub fooey : Exported {}
+
+1;
diff --git a/examples/fancy_example/BeerDB/Brewery.pm b/examples/fancy_example/BeerDB/Brewery.pm
new file mode 100644 (file)
index 0000000..ad99483
--- /dev/null
@@ -0,0 +1,10 @@
+package BeerDB::Brewery;
+use strict;
+use warnings;
+
+use Data::Dumper;
+
+sub display_columns { qw/name url beers/ } # note has_man beers
+sub list_columns { qw/name url/ } 
+
+1;
diff --git a/examples/fancy_example/BeerDB/Drinker.pm b/examples/fancy_example/BeerDB/Drinker.pm
new file mode 100644 (file)
index 0000000..db798fd
--- /dev/null
@@ -0,0 +1,48 @@
+package BeerDB::Drinker;
+use strict;
+use warnings;
+
+use Data::Dumper;
+
+__PACKAGE__->columns('Stringify' => qw/handle/);
+
+# A drinker is a person but we do not want to select who that person is 
+# from a list because this is a 1:1 relationship rather than a M:1. 
+# The no_select option tells AsForm not to bother making a select box
+
+__PACKAGE__->has_a(person => 'BeerDB::Person', no_select => 1);
+
+# Drinker drinks many beers at pubs if they are lucky. I like to specify the
+# name of the foreign key unless i can control the order that the
+# cdbi classes are created. CDBI does not guess very well the fk column.
+
+#__PACKAGE__->has_many(pints => 'BeerDB::Pint', 'drinker');
+
+# When we create a drinker we want to create a person as well
+# So tell AsForm to display the person inputs too.
+
+sub display_columns { qw/person handle/ }
+sub list_columns { qw/person handle/ }
+# AsForm and templates may check for search_colums when making 
+#sub search_columns { qw/person handle/ }
+
+# We need to tweak the cgi inputs a little. 
+# Since list is where addnew is, override that.
+# Person is a has_a rel and AsForm wont make foreign inputs automatically so
+# we manually do it.
+
+sub list : Exported {
+       my ($self, $r) = @_;
+       $self->SUPER::list($r);
+       my %cgi = $self->to_cgi;
+       $cgi{person} = $self->to_field('person', 'foreign_inputs');
+       $r->template_args->{classmetadata}{cgi} = \%cgi;
+       #$r->template_args->{classmetadata}{search_cgi} = $self->search_inputs;
+}
+
+
+       
+
+#sub foreign_input_delimiter { '__IMODDD__'}
+
+1;
diff --git a/examples/fancy_example/beerdb.sql b/examples/fancy_example/beerdb.sql
new file mode 100644 (file)
index 0000000..6089c94
--- /dev/null
@@ -0,0 +1,67 @@
+CREATE TABLE style (
+    id integer primary key auto_increment,
+    name varchar(60),
+    notes text
+);
+
+CREATE TABLE pub (
+    id integer primary key auto_increment,
+    name varchar(60),
+    url varchar(120),
+    notes text
+);
+
+CREATE TABLE handpump (
+    id integer primary key auto_increment,
+    beer integer,
+    pub integer
+);
+
+CREATE TABLE beer (
+    id integer primary key auto_increment,
+    brewery integer,
+    style integer,
+    name varchar(30),
+    score integer(2),
+    price varchar(12),
+    abv varchar(10),
+    notes text,
+       tasted date
+);
+
+CREATE TABLE brewery (
+    id integer  primary key auto_increment,
+    name varchar(30),
+    url varchar(50),
+    notes text
+);
+
+CREATE TABLE drinker (
+  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+  person INTEGER UNSIGNED NOT NULL,
+  handle VARCHAR(20) NOT NULL,
+  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY(id),
+  INDEX drinker_FKIndex1(person)
+);
+
+CREATE TABLE person (
+  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+  first_name VARCHAR(50) NULL,
+  sur_name VARCHAR(50) NULL,
+  dob DATE NULL,
+  username VARCHAR(20) NULL,
+  password VARCHAR(20) NULL,
+  email VARCHAR(255) NULL,
+  PRIMARY KEY(id)
+);
+
+CREATE TABLE pint (
+  id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+  drinker INTEGER UNSIGNED NOT NULL,
+  handpump INTEGER UNSIGNED NOT NULL,
+  date_and_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY(id)
+);
+
+
diff --git a/examples/fancy_example/templates/custom/addnew b/examples/fancy_example/templates/custom/addnew
new file mode 100644 (file)
index 0000000..7053240
--- /dev/null
@@ -0,0 +1,24 @@
+[%#
+
+=head1 addnew
+
+This is the interface to adding a new instance of an object. (or a new
+row in the database, if you want to look at it that way) It displays a
+form containing a list of HTML components for each of the columns in the
+table.
+
+=cut
+
+#%]
+[% tbl = classmetadata.table; %]
+
+<div id="addnew">
+<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
+<fieldset>
+<legend>Add a new [% config.TABLES.$tbl.singular || tbl | ucfirst | replace('_',' '); %] </legend>
+       [% INCLUDE display_inputs; %]
+    <input type="submit" name="create" value="create" />
+    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
+</fieldset>
+</form>
+</div>
diff --git a/examples/fancy_example/templates/custom/display_inputs b/examples/fancy_example/templates/custom/display_inputs
new file mode 100644 (file)
index 0000000..6baf703
--- /dev/null
@@ -0,0 +1,114 @@
+[%# 
+
+=head1 display_inputs
+
+This *RECURSIVELY* displays inputs for a hash of html elements
+
+Vars it needs: 
+   classmetadata-- the hash of bunch of data:
+   cgi -- inputs keyed on column names
+   table -- table inputs are for
+   columns -- list  in order want displayed inputs
+   colnames -- hash of what to label inputs
+   
+errors          -- hash of errors keyed on columns 
+
+
+TODO -- make it recognize a general submit button for redisplaying
+values on errors
+
+=cut
+
+#
+%]
+
+[% # some variables
+   foreign    = []; 
+   names      = [];
+   # get hash of related classes keyed on accessor for Foreign Inputs
+   USE this   = Class(classmetadata.name); 
+   tbl = classmetadata.table;
+   required = { }; 
+   FOR c IN request.config.$tbl.required_cols;
+        required.$c = 1;
+   END;
+
+%]     
+
+[% 
+SET heading_shown = 0; 
+FOR col = classmetadata.columns;  
+       NEXT IF !classmetadata.cgi.$col;
+       NEXT IF col == "id" OR col == classmetadata.table _ "_id";
+       # Display foreign inputs last 
+       IF (mykeys = classmetadata.cgi.$col.keys); 
+                       foreign.push(col);
+                       names.push(classmetadata.colnames.$col);
+                       NEXT;
+       END;
+    IF ! heading_shown; 
+       heading = classmetadata.moniker | ucfirst; 
+               "<h4> $heading </h4>";
+       SET heading_shown = 1; 
+    END;
+%]
+
+[%  # Base case starts here 
+
+       SET elem = classmetadata.cgi.$col; #.clone; # not sure why clone
+       IF elem.type == 'hidden'; 
+               elem.as_XML;
+               NEXT;
+       ELSIF  cgi_params;
+               param_col = col_prefix _ col;
+               IF elem.tag == "textarea";
+                       elem = elem.push_content(cgi_params.$param_col);
+               ELSIF elem.tag == "select";
+                       oldval = set_selected(elem, cgi_params.$col);
+               ELSE;
+                       oldval = elem.attr("value", cgi_params.$param_col);
+               END;
+       END;
+%]
+
+       <label>
+               [% indicator = '';
+           SET indicator = '*' IF (required.$col); 
+        %]
+               <span class="field">
+                   [% indicator _ classmetadata.colnames.$col || 
+                       col | replace('_',' ') | ucfirst  %] 
+               </span>
+               [% elem.as_XML; %]
+       </label>
+
+       [% IF errors.$col %]
+               <span class="error">[% errors.$col | html  %]</span>
+       [% END %]
+[% END; %]
+
+<!-- Display the differnt component inputs --> 
+
+[%     USE this = Class(classmetadata.name); 
+       FOR col IN foreign; 
+               # has_many mapping throws a stick in our spokes because related_class returns the mapped 
+               # class. Sometimes we just want the has_many class. 
+
+        # In case of Pub Handpumps maps to Beer and we want to add Handpump to Pub, we dont 
+               # want the mapped data .
+        # In case of "Create New Handpump" -- we want the mapped data probably so we get
+        # Beer inputs and Pub select box.
+
+               fclass_rel_meta = this.related_meta(request, col);
+        fclass = fclass_rel_meta.foreign_class; # ignor args.mapping
+               fclass_meta = this.get_classmetadata(fclass);
+               fclass_meta.cgi = classmetadata.cgi.$col;
+ #       USE Dumper; Dumper.dump(fclass_meta);
+               INCLUDE display_inputs
+                       col_prefix = col _ "__AF__" _ col_prefix
+                       errors = errors.$col
+                       heading = names.shift
+                       classmetadata = fclass_meta; # localize 
+       END;
+%]
+
diff --git a/examples/fancy_example/templates/custom/display_search_inputs b/examples/fancy_example/templates/custom/display_search_inputs
new file mode 100644 (file)
index 0000000..9985bfb
--- /dev/null
@@ -0,0 +1,63 @@
+[%# 
+
+=head1 display_search_inputs
+
+This displays inputs for search page.  Override in individual class template
+directories as needed. 
+
+Vars it needs: 
+classmetadata-- the hash of inputs keyed on column names
+errors          -- hash of errors keyed on columns 
+=cut
+
+#%]
+
+[% IF errors.FATAL; "FATAL ERROR: "; errors.FATAL; "<br>"; END %]
+
+[%     USE this = Class(classmetadata.name);
+       SET srch_fields = classmetadata.search_columns || 
+                         classmetadata.columns; 
+       SET cgi         = classmetadata.cgi; 
+       SET delimiter = this.foreign_input_delimiter;
+       FOR field IN srch_fields;
+               NEXT IF !cgi.$field;
+               # Recursivly call this tmeplate if we have foreign field 
+        # (hash of foreign inputs should come with it) 
+               IF (  cgi.$field.keys ); 
+               fclass = this.related_class(request, field); 
+                       fclass_meta = this.get_classmetadata(fclass);
+                       fclass_meta.cgi = cgi.$field; 
+                       tbl   = fclass_meta.table;
+                       INCLUDE display_search_inputs
+                               col_prefix    = col _ delimiter _ col_prefix
+                               classmetadata = fclass_meta;
+                       NEXT;
+               END;
+
+       NEXT IF field == 'id' OR field == classmetadata.table _ 'id';
+       SET element = cgi.$field; 
+%]
+
+<label>
+               <span class="field">
+               [% 
+                       classmetadata.colnames.$field || field | ucfirst | replace('_',' '); %]
+               </span>
+               [%      IF element.tag == "select";
+                               # set the previous value 
+                               IF cgi_params.exists(field);
+                                       set_selected(element, cgi_params.$field);
+                               END;
+                                       
+                       END;
+            IF element.tag == "input";  # wipe out any default value
+                         old_val =  element.attr('value', '');
+               END;
+       
+
+               element.as_XML; 
+               %]
+</label>
+[% END; %]
+       
+
diff --git a/examples/fancy_example/templates/custom/edit b/examples/fancy_example/templates/custom/edit
new file mode 100644 (file)
index 0000000..dae8c42
--- /dev/null
@@ -0,0 +1,72 @@
+[%#
+
+=head1 edit
+
+This is the edit page. It edits the passed-in object, by displaying a
+form similar to L<addnew> but with the current values filled in.
+
+=cut
+
+#%]
+[% PROCESS macros %]
+[% INCLUDE header %]
+[% INCLUDE title %]
+
+[% IF request.action == 'edit' %]
+[% INCLUDE navbar %]
+[% END %]
+
+[% IF objects.size %]
+<div id="title">Edit a [% classmetadata.moniker %]</div>
+[% FOR item = objects; %]
+<form action="[% base %]/[% item.table %]/do_edit/[% item.id %]" method="post">
+<fieldset>
+<legend>Edit [% item.name %]</legend>
+[% FOR col = classmetadata.columns;
+    NEXT IF col == "id" OR col == classmetadata.table _ "_id";
+    '<label><span class="field">';
+    classmetadata.colnames.$col || col | ucfirst | replace('_',' '); ":</span>";
+    item.to_field(col).as_XML;
+    "</label>";
+    IF errors.$col; 
+       '<span class="error">'; errors.$col;'</span>';
+    END;
+    END %]
+    <input type="submit" name="edit" value="edit"/>
+    <input type="hidden" name="__form_id" value="[% request.make_random_id %]">
+    </fieldset></form>
+    
+    [% END %]
+[% ELSE %]
+
+<div id="addnew">
+<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
+<fieldset>
+<legend>Add a new [% classmetadata.moniker %]</legend>
+    [% FOR col = classmetadata.columns %]
+        [% NEXT IF col == "id" %]
+            <label><span class="field">[% classmetadata.colnames.$col %]</span>
+            [% 
+            SET elem = classmetadata.cgi.$col.clone;
+            IF request.action == 'do_edit';
+                IF elem.tag == "textarea";
+                    elem = elem.push_content(request.param(col));
+                ELSE;
+                    elem.attr("value", request.param(col));
+                END;
+            END;
+            elem.as_XML; %]
+           </label>
+        [% IF errors.$col %]
+           <span class="error">[% errors.$col | html  %]</span>
+        [% END %]
+
+    [% END; %]
+    <input type="submit" name="create" value="create" />
+    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
+</fieldset>
+</form>
+</div>
+
+[% END %]
+[% INCLUDE footer %]
diff --git a/examples/fancy_example/templates/custom/header b/examples/fancy_example/templates/custom/header
new file mode 100644 (file)
index 0000000..c21fff7
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <title>
+            [%
+              title || config.application_name ||
+                "A poorly configured Maypole application"
+            %]
+        </title>
+        <meta http-equiv="Content-Type" content="text/html; charset=[% request.document_encoding %]" />
+       <base href="[% config.uri_base%]"/>
+        <link title="Maypole" href="maypole.css" type="text/css" rel="stylesheet" />
+   </head>
+    <body>
+        <div class="content">
diff --git a/examples/fancy_example/templates/custom/maypole.css b/examples/fancy_example/templates/custom/maypole.css
new file mode 100644 (file)
index 0000000..b13b4f1
--- /dev/null
@@ -0,0 +1,382 @@
+html {
+    padding-right: 0px;
+    padding-left: 0px; 
+    padding-bottom: 0px; 
+    margin: 0px; 
+    padding-top: 0px
+}
+body {
+    font-family: sans-serif;
+    padding-right: 0px; 
+    padding-left: 0px; 
+    padding-bottom: 0px;
+    margin: 0px; padding-top: 0px;
+    background-color: #fff;
+}
+#frontpage_list {
+    position: absolute;
+    z-index: 5;
+    padding: 0px 100px 0px 0px;
+    margin:0 0.5%;     
+    margin-bottom:1em; 
+    margin-top: 1em;
+    background-color: #fff;
+}
+
+#frontpage_list a:hover {
+    background-color: #d0d8e4;
+}
+
+#frontpage_list ul {
+    list-style-type: square;
+}
+
+.content {
+    padding: 12px;
+    margin-top: 1px;  
+    margin-bottom:0px;
+    margin-left: 15px; 
+    margin-right: 15px;
+    border-color: #000000;
+    border-top: 0px;
+    border-bottom: 0px;
+    border-left: 1px;
+    border-right: 1px;
+}
+
+A { 
+    text-decoration: none; 
+    color:#225 
+}
+A:hover { 
+    text-decoration: underline; 
+    color:#222 
+}
+
+#title {
+    z-index: 6;
+    width: 100%;
+    height: 18px;
+    margin-top: 10px;
+    font-size: 90%;
+    border-bottom: 1px solid #ddf;
+    text-align: left;
+}
+
+#subtitle {
+    postion: absolute;
+    z-index: 6;
+    padding: 10px;
+    margin-top: 2em;
+    height: 18px;
+    text-align: left;
+    background-color: #fff;
+}
+
+input[type=text] {
+    height: 16px;
+    width: 136px;
+    font-family: sans-serif;
+    font-size: 11px;
+    color: #2E415A;
+    padding: 0px;
+    margin-bottom: 5px;
+}
+
+input[type=submit] {
+    height: 18px;
+    width: 60px;
+    font-family: sans-serif;
+    font-size: 11px;
+    border: 1px outset;
+    background-color: #fff;
+    padding: 0px 0px 2px 0px;
+    margin-bottom: 5px;
+}
+
+input:hover[type=submit] {
+    color: #fff;
+    background-color: #7d95b5;
+}
+
+textarea {
+    width: 136px;
+    font-family: sans-serif;
+    font-size: 11px;
+    color: #2E415A;
+    padding: 0px;
+    margin-bottom: 5px;
+}
+
+select {
+    height: 16px;
+    width: 140px;
+    font-family: sans-serif;
+    font-size: 12px;
+    color: #202020;
+    padding: 0px;
+    margin-bottom: 5px;
+}
+
+.deco1 {
+    font-size: 0px;
+    z-index:1;
+    border:0px;
+    border-style:solid;
+    border-color:#4d6d99;
+    background-color:#4d6d99;
+}
+
+.deco2 {
+    z-index:2;
+    border:0px;
+    border-style:solid;
+    border-color:#627ea5;
+    background-color:#627ea5;
+}
+
+
+.deco3 {
+    z-index:3;
+    border:0px;
+    border-style:solid;
+    border-color:#7d95b5;
+    background-color:#7d95b5;
+}
+                   
+.deco4 {
+    z-index:4;
+    border:0px;
+    border-style:solid;
+    border-color:#d0d8e4;
+    background-color:#d0d8e4;
+}
+                   
+
+table { 
+    border: 0px solid; 
+    background-color: #ffffff;
+}
+
+#matrix { width: 100%; }
+
+#matrix th {
+    background-color: #b5cadc;
+    border: 1px solid #778;
+    font: bold 12px Verdana, sans-serif;
+}
+
+#matrix #actionth {
+    width: 1px; 
+    padding: 0em 1em 0em 1em;
+}
+
+#matrix tr.alternate { background-color:#e3eaf0; }
+#matrix tr:hover { background-color: #b5cadc; }
+#matrix td { font: 12px Verdana, sans-serif; }
+
+#navlist {
+    padding: 3px 0;
+    margin-left: 0;
+    margin-top:3em;
+    border-bottom: 1px solid #778;
+    font: bold 12px Verdana, sans-serif;
+}
+
+#navlist li {
+    list-style: none;
+    margin: 0;
+    display: inline;
+}
+
+#navlist li a {
+    padding: 3px 0.5em;
+    margin-left: 3px;
+    border: 1px solid #778;
+    border-bottom: none;
+    background: #b5cadc;
+    text-decoration: none;
+}
+
+#navlist li a:link { color: #448; }
+#navlist li a:visited { color: #667; }
+
+#navlist li a:hover {
+    color: #000;
+    background: #eef;
+    border-top: 4px solid #7d95b5;
+    border-color: #227;
+}
+
+#navlist #active a {
+    background: white;
+    border-bottom: 1px solid white;
+    border-top: 4px solid;
+}
+
+td { font: 12px Verdana, sans-serif; }
+
+
+fieldset {
+    margin-top: 1em;
+    padding: 1em;
+    background-color: #f3f6f8;
+    font:80%/1 sans-serif;
+    border:1px solid #ddd;
+}
+
+legend {
+    padding: 0.2em 0.5em;
+    background-color: #fff;
+    border:1px solid #aaa;
+    font-size:90%;
+    text-align:right;
+}
+
+label {
+    display:block;
+}
+
+label.error {
+    display:block;
+       border-color: red;
+       border-width: 1px;
+}
+
+label .field {
+    float:left;
+    width:25%;
+    margin-right:0.5em;
+    padding-top:0.2em;
+    text-align:right;
+    font-weight:bold;
+}
+
+#vlist {
+    padding: 0 1px 1px;
+    margin-left: 0;
+    font: bold 12px Verdana, sans-serif;
+    background: gray;
+    width: 13em;
+}
+
+#vlist li {
+    list-style: none;
+    margin: 0;
+    border-top: 1px solid gray;
+    text-align: left;
+}
+
+#vlist li a {
+    display: block;
+    padding: 0.25em 0.5em 0.25em 0.75em;
+    border-left: 1em solid #7d95b5;
+    background: #d0d8e4;
+    text-decoration: none;
+}
+
+#vlist li a:hover { 
+    border-color: #227;
+}
+
+.view .field {
+    background-color: #f3f6f8;
+    border-left: 1px solid #7695b5;
+    border-top: 1px solid #7695b5;
+    padding: 1px 10px 0px 2px;
+}
+
+#addnew {
+    width: 50%;
+    float: left;
+}
+
+#search {
+    width: 50%;
+    float:right;
+}
+
+.error { color: #d00; }
+
+.action {
+    border: 1px outset #7d95b5;
+    style:block;
+}
+
+.action:hover {
+    color: #fff;
+    text-decoration: none;
+    background-color: #7d95b5;
+}
+
+.actionform {
+    display: inline;
+}
+
+.actionbutton {
+    height: 16px;
+    width: 40px;
+    font-family: sans-serif;
+    font-size: 10px;
+    border: 1px outset;
+    background-color: #fff;
+    margin-bottom: 0px;
+}
+
+.actionbutton:hover {
+    color: #fff;
+    background-color: #7d95b5;
+}
+
+.actions {
+    white-space: nowrap;
+}
+
+.field {
+    display:inline;
+}
+
+#login { width: 400px; }
+
+#login input[type=text] { width: 150px; }
+#login input[type=password] { width: 150px; }
+
+.pager {
+    font: 11px Arial, Helvetica, sans-serif;
+    text-align: center;
+    border: solid 1px #e2e2e2;
+    border-left: 0;
+    border-right: 0;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    margin: 0px;
+    background-color: #f3f6f8;
+}
+
+.pager a {
+    padding: 2px 6px;
+    border: solid 1px #ddd;
+    background: #fff;
+    text-decoration: none;
+}
+
+.pager a:visited {
+    padding: 2px 6px;
+    border: solid 1px #ddd;
+    background: #fff;
+    text-decoration: none;
+}
+
+.pager .current-page {
+    padding: 2px 6px;
+    font-weight: bold;
+    vertical-align: top;
+}
+
+.pager a:hover {
+    color: #fff;
+    background: #7d95b5;
+    border-color: #036;
+    text-decoration: none;
+}
+
diff --git a/examples/fancy_example/templates/custom/metadata b/examples/fancy_example/templates/custom/metadata
new file mode 100644 (file)
index 0000000..e15fb6a
--- /dev/null
@@ -0,0 +1,5 @@
+<h3> Class::DBI meta info for [% classmetadata.name %] </h3> 
+[%
+   USE this = Class(classmetadata.name);
+   USE Dumper; Dumper.dump(this.meta_info);
+%]
diff --git a/examples/fancy_example/templates/custom/search_form b/examples/fancy_example/templates/custom/search_form
new file mode 100644 (file)
index 0000000..5d540fb
--- /dev/null
@@ -0,0 +1,9 @@
+<div id="search">
+<form method="get" action="[% base %]/[% classmetadata.table %]/search/">
+<fieldset>
+<legend>Search</legend>
+    [% INCLUDE display_search_inputs; %] 
+    <input type="submit" name="search" value="search"/>
+</fieldset>
+</form>
+</div>
diff --git a/examples/fancy_example/templates/factory/addnew b/examples/fancy_example/templates/factory/addnew
new file mode 100644 (file)
index 0000000..2334496
--- /dev/null
@@ -0,0 +1,41 @@
+[%#
+
+=head1 addnew
+
+This is the interface to adding a new instance of an object. (or a new
+row in the database, if you want to look at it that way) It displays a
+form containing a list of HTML components for each of the columns in the
+table.
+
+=cut
+
+#%]
+
+<div id="addnew">
+<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
+    <fieldset>
+<legend>Add a new [% classmetadata.moniker %]</legend>
+    [% FOR col = classmetadata.columns %]
+        [% NEXT IF col == "id" %]
+            <label><span class="field">[% classmetadata.colnames.$col %]</span>
+            [% 
+            SET elem = classmetadata.cgi.$col.clone;
+            IF request.action == 'do_edit';
+                IF elem.tag == "textarea";
+                    elem = elem.push_content(request.param(col));
+                ELSE;
+                    elem.attr("value", request.param(col));
+                END;
+            END;
+            elem.as_XML; %]
+           </label>
+        [% IF errors.$col %]
+           <span class="error">[% errors.$col | html  %]</span>
+        [% END %]
+
+    [% END; %]
+    <input type="submit" name="create" value="create" />
+    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
+</fieldset>
+</form>
+</div>
diff --git a/examples/fancy_example/templates/factory/edit b/examples/fancy_example/templates/factory/edit
new file mode 100644 (file)
index 0000000..cf88311
--- /dev/null
@@ -0,0 +1,70 @@
+[%#
+
+=head1 edit
+
+This is the edit page. It edits the passed-in object, by displaying a
+form similar to L<addnew> but with the current values filled in.
+
+=cut
+
+#%]
+[% PROCESS macros %]
+[% INCLUDE header %]
+[% INCLUDE title %]
+
+[% IF request.action == 'edit' %]
+[% INCLUDE navbar %]
+[% END %]
+
+[% IF object %]
+<div id="title">Edit a [% classmetadata.moniker %]</div>
+<form action="[% base %]/[% item.table %]/do_edit/[% item.id %]" method="post">
+<fieldset>
+<legend>Edit [% object.name %]</legend>
+   [% FOR col = classmetadata.columns;
+    NEXT IF col == "id" OR col == classmetadata.table _ "_id";
+    '<label><span class="field">';
+    classmetadata.colnames.$col || col | ucfirst | replace('_',' '); ":</span>";
+    object.to_field(col).as_XML;
+    "</label>";
+    IF errors.$col; 
+       '<span class="error">'; errors.$col;'</span>';
+    END;
+    END %]
+    <input type="submit" name="edit" value="edit"/>
+    <input type="hidden" name="__form_id" value="[% request.make_random_id %]">
+    </fieldset></form>
+    
+[% ELSE %]
+
+<div id="addnew">
+<form method="post" action="[% base %]/[% classmetadata.table %]/do_edit/">
+<fieldset>
+<legend>Add a new [% classmetadata.moniker %]</legend>
+    [% FOR col = classmetadata.columns %]
+        [% NEXT IF col == "id" %]
+            <label><span class="field">[% classmetadata.colnames.$col %]</span>
+            [% 
+            SET elem = classmetadata.cgi.$col.clone;
+            IF request.action == 'do_edit';
+                IF elem.tag == "textarea";
+                    elem = elem.push_content(request.param(col));
+                ELSE;
+                    elem.attr("value", request.param(col));
+                END;
+            END;
+            elem.as_XML; %]
+           </label>
+        [% IF errors.$col %]
+           <span class="error">[% errors.$col | html  %]</span>
+        [% END %]
+
+    [% END; %]
+    <input type="submit" name="create" value="create" />
+    <input type="hidden" name="__form_id" value="[% request.make_random_id %]" />
+</fieldset>
+</form>
+</div>
+
+[% END %]
+[% INCLUDE footer %]
diff --git a/examples/fancy_example/templates/factory/footer b/examples/fancy_example/templates/factory/footer
new file mode 100644 (file)
index 0000000..1b8ae55
--- /dev/null
@@ -0,0 +1,3 @@
+       </div>
+    </body>
+</html>
diff --git a/examples/fancy_example/templates/factory/frontpage b/examples/fancy_example/templates/factory/frontpage
new file mode 100644 (file)
index 0000000..ac47269
--- /dev/null
@@ -0,0 +1,27 @@
+[%#
+
+=head1 frontpage
+
+This is the frontpage for your Maypole application.
+It shows a list of all tables it is allowed to display.
+
+=cut
+
+#%]
+[% INCLUDE header %]
+<div id="title">
+    [% config.application_name || "A poorly configured Maypole application" %]
+</div>
+<div id="frontpage_list">
+<ul>
+[% FOR table = config.display_tables %]
+    <li>
+        <a href="[% base %]/[%table%]/list">List by [%table %]</a>
+    </li>      
+[% END %]
+</ul>
+</div>
+
+[% INCLUDE maypole %]
+
+[% INCLUDE footer %]
diff --git a/examples/fancy_example/templates/factory/header b/examples/fancy_example/templates/factory/header
new file mode 100644 (file)
index 0000000..ba0b190
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <title>
+            [%
+              title || config.application_name ||
+                "A poorly configured Maypole application"
+            %]
+        </title>
+        <meta http-equiv="Content-Type" content="text/html; charset=[% request.document_encoding %]" />
+       <base href="[% config.uri_base%]"/>
+        <link title="Maypole" href="[% config.uri_base %]/maypole.css" type="text/css" rel="stylesheet" />
+   </head>
+    <body>
+        <div class="content">
diff --git a/examples/fancy_example/templates/factory/list b/examples/fancy_example/templates/factory/list
new file mode 100644 (file)
index 0000000..9abbc01
--- /dev/null
@@ -0,0 +1,63 @@
+[% PROCESS macros %]
+[% INCLUDE header %]
+[% INCLUDE title %]
+[% IF search %]
+    <div id="title">Search results</div>
+[% ELSE %]
+    <div id="title">Listing of all [% classmetadata.plural %]</div>
+[% END %]
+[% INCLUDE navbar %]
+<div class="list">
+    <table id="matrix">
+        <tr>
+            [% FOR col = classmetadata.list_columns.list;
+                NEXT IF col == "id" OR col == classmetadata.table _ "_id";
+                "<th>"; 
+                SET additional = "?order=" _ col;
+                SET additional = additional _ "&page=" _ pager.current_page
+                    IF pager;
+                SET additional = additional _ "&o2=desc" 
+                IF col == request.params.order and request.params.o2 != "desc";
+                SET action = "list";
+                FOR name = classmetadata.columns.list;
+                  IF request.query.$name;
+                    SET additional =
+                        additional  _ "&" _ name _ "=" _
+                        request.params.$name;
+                    SET action = "search";
+                  END;
+                END;
+               USE model_obj = Class request.model_class;
+               IF model_obj.find_column(col);
+                  link(classmetadata.table, action, additional,
+                    classmetadata.colnames.$col);
+                  IF col == request.params.order;
+                    IF request.params.o2 != "desc";
+                        "&darr;";
+                    ELSE;
+                        "&uarr;";
+                    END;
+                  END;
+               ELSE;
+                 classmetadata.colnames.$col || col FILTER ucfirst;
+               END;
+                "</th>";
+            END %]
+           <th id="actionth">Actions</th>
+        </tr>
+        [%  SET count = 0;
+        FOR item = objects;
+            SET count = count + 1;
+            "<tr";
+            ' class="alternate"' IF count % 2;
+            ">";
+            display_line(item);
+            "</tr>";
+        END %]
+    </table>
+
+[% INCLUDE pager %]
+[% INCLUDE addnew %]
+[% INCLUDE search_form %]
+</div>
+[% INCLUDE footer %]
diff --git a/examples/fancy_example/templates/factory/login b/examples/fancy_example/templates/factory/login
new file mode 100644 (file)
index 0000000..af08e5b
--- /dev/null
@@ -0,0 +1,27 @@
+[% PROCESS macros %]
+[% INCLUDE header %]
+[% INCLUDE title %]
+[% user_field = config.auth.user_field || "user" %]
+
+    <div id="title">You need to log in</div>
+
+    <div id="login">
+    [% IF login_error %]
+        <div class="error"> [% login_error | html %] </div>
+    [% END %]
+    <form method="post" action="[% base %]/[% request.path %]">
+    <fieldset>
+    <legend>Login</legend>
+        <label>
+            <span class="field">Username:</span>
+           <input name="[% user_field %]" type="text" value="[% cgi_params.$user_field | html %]" />
+        </label>
+       <label>
+           <span class="field">Password:</span>
+                   <input name="password" type="password" value="[% cgi_params.passwrd | html %]"/>
+       </label>        
+        <input type="submit" name="login" value="Submit"/>
+    </fieldset>
+    </form>
+    </div>
+
diff --git a/examples/fancy_example/templates/factory/macros b/examples/fancy_example/templates/factory/macros
new file mode 100644 (file)
index 0000000..fc75d09
--- /dev/null
@@ -0,0 +1,185 @@
+[%#
+
+=head1 MACROS
+
+These are some default macros which are used by various templates in the
+system.
+
+=head2 link
+
+This creates an <A HREF="..."> to a command in the Apache::MVC system by
+catenating the base URL, table, command, and any arguments.
+
+#%]
+[%
+MACRO link(table, command, additional, label) BLOCK;
+    SET lnk = base _ "/" _ table _ "/" _ command _ "/" _ additional;
+    lnk = lnk | uri | html;
+    '<a href="' _ lnk _ '">';
+    label | html;
+    "</a>";
+END;
+%]
+
+[%#
+
+=head2 maybe_link_view
+
+C<maybe_link_view> takes something returned from the database - either
+some ordinary data, or an object in a related class expanded by a
+has-a relationship. If it is an object, it constructs a link to the view
+command for that object. Otherwise, it just displays the data.
+
+#%]
+
+[%
+MACRO maybe_link_view(object) BLOCK;
+    IF object.isa('Maypole::Model::Base');
+        link(object.table, "view", object.id.join('/'), object);
+    ELSE;
+        object | html ;
+    END;
+END;
+%]
+
+[%#
+
+=head2 display_line
+
+C<display_line> is used in the list template to display a row from the
+database, by iterating over the columns and displaying the data for each
+column. It misses out the C<id> column by default, and magically
+URLifies columns called C<url>. This may be considered too much magic
+for some.
+
+#%]
+[% MACRO display_line(item) BLOCK;
+    FOR col = classmetadata.list_columns;
+       NEXT IF col == "id" OR col == classmetadata.table _ "_id";
+       col_obj = item.find_column(col);
+        "<td>";
+        IF col == "url" AND item.url;
+            '<a href="'; item.url | html ; '"> '; item.url; '</a>';
+        ELSIF col == classmetadata.stringify_column;
+            maybe_link_view(item);
+               ELSIF col_obj; # its a real column
+            accessor = item.accessor_name_for(col_obj) ||
+                                  item.accessor_name(col_obj); # deprecated in cdbi
+            maybe_link_view(item.$accessor);
+        ELSE; 
+            item.$col;
+        END;
+
+        "</td>";
+    END;
+    '<td class="actions">';
+    button(item, "edit");
+    button(item, "delete");
+    "</td>";
+END %]
+[%#
+
+=head2 button
+
+This is a generic button, which performs an action on an object.
+
+=cut
+
+#%]
+[% MACRO button(obj, action) BLOCK; %]
+[% IF obj.is_public(action) %]
+<form class="actionform" action="[% base %]/[% obj.table %]/[% action %]/[% obj.id.join('/') %]" method="post">
+<div class="field"><input class="actionbutton" type="submit" value="[% action %]" /></div></form>
+[% END %]
+[% END %]
+[%#
+
+=head2 view_related
+
+This takes an object, and looks up the C<related_accessors>; this should
+give a list of accessors that can be called to get a list of related
+objects. It then displays a title for that accessor, (i.e. "Beers" for a
+brewery) calls the accesor, and displays a list of the results. 
+
+=cut
+
+#%]
+[% 
+MACRO view_related(object) BLOCK;
+    FOR accessor = classmetadata.related_accessors.list;
+        "<div id=\"subtitle\">"; accessor | ucfirst; "</div>\n";
+        "<ul id=\"vlist\">";
+        FOR thing = object.$accessor;
+            "<li>"; maybe_link_view(thing); "</li>\n";
+        END;
+        "</ul>";
+    END; 
+END;
+
+MACRO test_xxxx(myblock) BLOCK;
+    FOR col = classmetadata.columns;
+        NEXT IF col == "id";
+        myblock;
+    END;
+END;
+%]
+[%#
+
+=head2 view_item
+
+This takes an object and and displays its properties in a table. 
+
+=cut
+
+#%]
+[% MACRO view_item(item) BLOCK; %]
+    [% SET string = classmetadata.stringify_column %]
+    <div id="title"> [% item.$string | html %]</div>
+    [% INCLUDE navbar %]
+    <table class="view">
+        <tr>
+            <td class="field">[% classmetadata.colnames.$string  %]</td>
+            <td>[% item.$string | html %]</td>
+        </tr>
+        [% FOR col = classmetadata.columns.list;
+            NEXT IF col == "id" OR col == string OR col == classmetadata.table _ "_id";;
+            NEXT UNLESS item.$col;
+        %]
+[%# 
+
+=for doc
+
+It gets the displayable form of a column's name from the hash returned
+from the C<column_names> method:
+
+#%]
+            <tr>
+                <td class="field">[% classmetadata.colnames.$col || 
+                     col | ucfirst | replace('_',' '); %]</td>
+                <td>
+                    [% IF col == "url" && item.url;  # Possibly too much magic.
+                        '<a href="'; item.url | html ; '"> '; item.url; '</a>';
+                                       ELSIF item.$col.size > 1; # has_many column
+                                               FOR thing IN item.$col; 
+                                                       maybe_link_view(thing);",  ";
+                                                END;
+
+                    ELSE;
+                        maybe_link_view(item.$col); 
+                    END; %]
+[%#
+
+This tests whether or not the returned value is an object, and if so,
+creates a link to a page viewing that object; if not, it just displays
+the text as normal. The object is linked using its stringified name;
+by default this calls the C<name> method, or returns the object's ID
+if there is no C<name> method or other stringification method defined.
+
+=cut
+
+#%] 
+                </td>
+            </tr>
+        [% END; %]
+    </table>
+[% END %]
diff --git a/examples/fancy_example/templates/factory/maypole b/examples/fancy_example/templates/factory/maypole
new file mode 100644 (file)
index 0000000..7ab2744
--- /dev/null
@@ -0,0 +1,7 @@
+<!-- boxes -->
+<div style='position:absolute;top:220px;left:130px;border-bottom-width:260px;border-right-width:370px;' class='deco1'>&nbsp;</div>
+<div style='position:absolute;top:260px;left:190px;border-bottom-width:170px;border-right-width:530px;' class='deco2'>&nbsp;</div>
+<div style='position:absolute;top:240px;left:220px;border-bottom-width:340px;border-right-width:440px;' class='deco4'>&nbsp;</div>
+<div style='position:absolute;top:160px;left:330px;border-bottom-width:160px;border-right-width:280px;' class='deco1'>&nbsp;</div>
+<div style='position:absolute;top:190px;left:290px;border-bottom-width:430px;border-right-width:130px;' class='deco2'>&nbsp;</div>
+<!-- end of boxes -->
diff --git a/examples/fancy_example/templates/factory/maypole.css b/examples/fancy_example/templates/factory/maypole.css
new file mode 100644 (file)
index 0000000..d63be55
--- /dev/null
@@ -0,0 +1,381 @@
+html {
+    padding-right: 0px;
+    padding-left: 0px; 
+    padding-bottom: 0px; 
+    margin: 0px; 
+    padding-top: 0px
+}
+body {
+    font-family: sans-serif;
+    padding-right: 0px; 
+    padding-left: 0px; 
+    padding-bottom: 0px;
+    margin: 0px; padding-top: 0px;
+    background-color: #fff;
+}
+#frontpage_list {
+    position: absolute;
+    z-index: 5;
+    padding: 0px 100px 0px 0px;
+    margin:0 0.5%;     
+    margin-bottom:1em; 
+    margin-top: 1em;
+    background-color: #fff;
+}
+
+#frontpage_list a:hover {
+    background-color: #d0d8e4;
+}
+
+#frontpage_list ul {
+    list-style-type: square;
+}
+
+.content {
+    padding: 12px;
+    margin-top: 1px;  
+    margin-bottom:0px;
+    margin-left: 15px; 
+    margin-right: 15px;
+    border-color: #000000;
+    border-top: 0px;
+    border-bottom: 0px;
+    border-left: 1px;
+    border-right: 1px;
+}
+
+A { 
+    text-decoration: none; 
+    color:#225 
+}
+A:hover { 
+    text-decoration: underline; 
+    color:#222 
+}
+
+#title {
+    z-index: 6;
+    width: 100%;
+    height: 18px;
+    margin-top: 10px;
+    font-size: 90%;
+    border-bottom: 1px solid #ddf;
+    text-align: left;
+}
+
+#subtitle {
+    postion: absolute;
+    z-index: 6;
+    padding: 10px;
+    margin-top: 2em;
+    height: 18px;
+    text-align: left;
+    background-color: #fff;
+}
+
+input[type=text] {
+    height: 16px;
+    width: 136px;
+    font-family: sans-serif;
+    font-size: 11px;
+    color: #2E415A;
+    padding: 0px;
+    margin-bottom: 5px;
+}
+
+input[type=submit] {
+    height: 18px;
+    width: 60px;
+    font-family: sans-serif;
+    font-size: 11px;
+    border: 1px outset;
+    background-color: #fff;
+    padding: 0px 0px 2px 0px;
+    margin-bottom: 5px;
+}
+
+input:hover[type=submit] {
+    color: #fff;
+    background-color: #7d95b5;
+}
+
+textarea {
+    width: 136px;
+    font-family: sans-serif;
+    font-size: 11px;
+    color: #2E415A;
+    padding: 0px;
+    margin-bottom: 5px;
+}
+
+select {
+    height: 16px;
+    width: 140px;
+    font-family: sans-serif;
+    font-size: 12px;
+    color: #202020;
+    padding: 0px;
+    margin-bottom: 5px;
+}
+
+.deco1 {
+    font-size: 0px;
+    z-index:1;
+    border:0px;
+    border-style:solid;
+    border-color:#4d6d99;
+    background-color:#4d6d99;
+}
+
+.deco2 {
+    z-index:2;
+    border:0px;
+    border-style:solid;
+    border-color:#627ea5;
+    background-color:#627ea5;
+}
+
+
+.deco3 {
+    z-index:3;
+    border:0px;
+    border-style:solid;
+    border-color:#7d95b5;
+    background-color:#7d95b5;
+}
+                   
+.deco4 {
+    z-index:4;
+    border:0px;
+    border-style:solid;
+    border-color:#d0d8e4;
+    background-color:#d0d8e4;
+}
+                   
+
+table { 
+    border: 0px solid; 
+    background-color: #ffffff;
+}
+
+#matrix { width: 100%; }
+
+#matrix th {
+    background-color: #b5cadc;
+    border: 1px solid #778;
+    font: bold 12px Verdana, sans-serif;
+}
+
+#matrix #actionth {
+    width: 1px; 
+    padding: 0em 1em 0em 1em;
+}
+
+#matrix tr.alternate { background-color:#e3eaf0; }
+#matrix tr:hover { background-color: #b5cadc; }
+#matrix td { font: 12px Verdana, sans-serif; }
+
+#navlist {
+    padding: 3px 0;
+    margin-left: 0;
+    margin-top:3em;
+    border-bottom: 1px solid #778;
+    font: bold 12px Verdana, sans-serif;
+}
+
+#navlist li {
+    list-style: none;
+    margin: 0;
+    display: inline;
+}
+
+#navlist li a {
+    padding: 3px 0.5em;
+    margin-left: 3px;
+    border: 1px solid #778;
+    border-bottom: none;
+    background: #b5cadc;
+    text-decoration: none;
+}
+
+#navlist li a:link { color: #448; }
+#navlist li a:visited { color: #667; }
+
+#navlist li a:hover {
+    color: #000;
+    background: #eef;
+    border-top: 4px solid #7d95b5;
+    border-color: #227;
+}
+
+#navlist #active a {
+    background: white;
+    border-bottom: 1px solid white;
+    border-top: 4px solid;
+}
+
+td { font: 12px Verdana, sans-serif; }
+
+
+fieldset {
+    margin-top: 1em;
+    padding: 1em;
+    background-color: #f3f6f8;
+    font:80%/1 sans-serif;
+    border:1px solid #ddd;
+}
+
+legend {
+    padding: 0.2em 0.5em;
+    background-color: #fff;
+    border:1px solid #aaa;
+    font-size:90%;
+    text-align:right;
+}
+
+label {
+    display:block;
+}
+
+label.error {
+       border-color: red;
+       border-width: 1px;
+}
+
+label .field {
+    float:left;
+    width:25%;
+    margin-right:0.5em;
+    padding-top:0.2em;
+    text-align:right;
+    font-weight:bold;
+}
+
+#vlist {
+    padding: 0 1px 1px;
+    margin-left: 0;
+    font: bold 12px Verdana, sans-serif;
+    background: gray;
+    width: 13em;
+}
+
+#vlist li {
+    list-style: none;
+    margin: 0;
+    border-top: 1px solid gray;
+    text-align: left;
+}
+
+#vlist li a {
+    display: block;
+    padding: 0.25em 0.5em 0.25em 0.75em;
+    border-left: 1em solid #7d95b5;
+    background: #d0d8e4;
+    text-decoration: none;
+}
+
+#vlist li a:hover { 
+    border-color: #227;
+}
+
+.view .field {
+    background-color: #f3f6f8;
+    border-left: 1px solid #7695b5;
+    border-top: 1px solid #7695b5;
+    padding: 1px 10px 0px 2px;
+}
+
+#addnew {
+    width: 50%;
+    float: left;
+}
+
+#search {
+    width: 50%;
+    float:right;
+}
+
+.error { color: #d00; }
+
+.action {
+    border: 1px outset #7d95b5;
+    style:block;
+}
+
+.action:hover {
+    color: #fff;
+    text-decoration: none;
+    background-color: #7d95b5;
+}
+
+.actionform {
+    display: inline;
+}
+
+.actionbutton {
+    height: 16px;
+    width: 40px;
+    font-family: sans-serif;
+    font-size: 10px;
+    border: 1px outset;
+    background-color: #fff;
+    margin-bottom: 0px;
+}
+
+.actionbutton:hover {
+    color: #fff;
+    background-color: #7d95b5;
+}
+
+.actions {
+    white-space: nowrap;
+}
+
+.field {
+    display:inline;
+}
+
+#login { width: 400px; }
+
+#login input[type=text] { width: 150px; }
+#login input[type=password] { width: 150px; }
+
+.pager {
+    font: 11px Arial, Helvetica, sans-serif;
+    text-align: center;
+    border: solid 1px #e2e2e2;
+    border-left: 0;
+    border-right: 0;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    margin: 0px;
+    background-color: #f3f6f8;
+}
+
+.pager a {
+    padding: 2px 6px;
+    border: solid 1px #ddd;
+    background: #fff;
+    text-decoration: none;
+}
+
+.pager a:visited {
+    padding: 2px 6px;
+    border: solid 1px #ddd;
+    background: #fff;
+    text-decoration: none;
+}
+
+.pager .current-page {
+    padding: 2px 6px;
+    font-weight: bold;
+    vertical-align: top;
+}
+
+.pager a:hover {
+    color: #fff;
+    background: #7d95b5;
+    border-color: #036;
+    text-decoration: none;
+}
+
diff --git a/examples/fancy_example/templates/factory/navbar b/examples/fancy_example/templates/factory/navbar
new file mode 100644 (file)
index 0000000..0c8b168
--- /dev/null
@@ -0,0 +1,22 @@
+[%#
+
+=head1 navbar
+
+This is a navigation bar to go across the page. (Or down the side, or
+whatetver you want to do with it.) It displays all the tables which are
+accessible, with a link to the list page for each one.
+
+#%]
+[% PROCESS macros %]
+<div id="navcontainer">
+<ul id="navlist">
+[%
+    FOR table = config.display_tables;
+        '<li '; 'id="active"' IF table == classmetadata.table; '>';
+        # Hack
+        link(table, "list", "", table);
+        '</li>';
+    END;
+%]
+</ul>
+</div> 
diff --git a/examples/fancy_example/templates/factory/pager b/examples/fancy_example/templates/factory/pager
new file mode 100644 (file)
index 0000000..78c89fd
--- /dev/null
@@ -0,0 +1,48 @@
+[%#
+
+=head1 pager
+
+This controls the pager display at the bottom (by default) of the list
+and search views. It expects a C<pager> template argument which responds
+to the L<Data::Page> interface.
+
+#%]
+[%
+IF pager AND pager.first_page != pager.last_page;
+%]
+<p class="pager">Pages: 
+[%
+    UNLESS pager_action;
+       SET pager_action = request.action;
+    END;
+   
+    SET begin_page = pager.current_page - 10;
+    IF begin_page < 1;
+        SET begin_page = pager.first_page;
+    END;
+    SET end_page = pager.current_page + 10;
+    IF pager.last_page < end_page;
+        SET end_page = pager.last_page;
+    END;
+     FOREACH num = [begin_page .. end_page];
+          IF num == pager.current_page;
+            "<span class='current-page'>"; num; "</span>";
+          ELSE;
+            SET label = num;
+            SET args = "?page=" _ num;
+           SET args = args _ "&order=" _ request.params.order
+             IF request.params.order;
+           SET args = args _ "&amp;o2=desc"
+             IF request.params.o2 == "desc";
+            FOR col = classmetadata.columns.list;
+              IF request.params.$col;
+                SET args = args _ "&" _ col _ "=" _ request.params.$col;
+                SET action = "search";
+              END;
+            END;
+            link(classmetadata.table, pager_action, args, label);
+          END;
+     END;
+%]
+</p>
+[% END %]
diff --git a/examples/fancy_example/templates/factory/search_form b/examples/fancy_example/templates/factory/search_form
new file mode 100644 (file)
index 0000000..d10101e
--- /dev/null
@@ -0,0 +1,22 @@
+<div id="search">
+<form method="get" action="[% base %]/[% classmetadata.moniker %]/search/">
+<fieldset>
+<legend>Search</legend>
+        [% FOR col = classmetadata.columns;
+            NEXT IF col == "id" OR col == classmetadata.table _ "_id";
+         %]
+           <label>
+                <span class="field">[% classmetadata.colnames.$col; %]</span>
+                    [% SET element = classmetadata.cgi.$col;
+                    IF element.tag == "select";
+                        USE element_maker = Class("HTML::Element");
+                        SET element = element.unshift_content(
+                            element_maker.new("option", value," "));
+                    END;
+                   element.as_XML; %]
+                  </label>
+        [% END; %]
+    <input type="submit" name="search" value="search"/>
+    </fieldset>
+</form>
+</div>
diff --git a/examples/fancy_example/templates/factory/search_form_recursive b/examples/fancy_example/templates/factory/search_form_recursive
new file mode 100644 (file)
index 0000000..5d540fb
--- /dev/null
@@ -0,0 +1,9 @@
+<div id="search">
+<form method="get" action="[% base %]/[% classmetadata.table %]/search/">
+<fieldset>
+<legend>Search</legend>
+    [% INCLUDE display_search_inputs; %] 
+    <input type="submit" name="search" value="search"/>
+</fieldset>
+</form>
+</div>
diff --git a/examples/fancy_example/templates/factory/title b/examples/fancy_example/templates/factory/title
new file mode 100644 (file)
index 0000000..401f0a3
--- /dev/null
@@ -0,0 +1 @@
+    <a href="[% base %]/frontpage">[% config.application_name %]</a>
diff --git a/examples/fancy_example/templates/factory/view b/examples/fancy_example/templates/factory/view
new file mode 100644 (file)
index 0000000..9f06086
--- /dev/null
@@ -0,0 +1,32 @@
+[%#
+
+=for doc
+
+The C<view> template takes some objects (usually just one) from
+C<objects> and displays the object's properties in a table. 
+
+=cut
+
+#%]
+[% PROCESS macros %]
+[% INCLUDE header %]
+[% view_item(object); %]
+[%#
+
+=for doc
+
+The C<view> template also displays a list of other objects related to the first
+one via C<has_many> style relationships; this is done by calling the
+C<related_accessors> method - see L<Model/related_accessors> - to return
+a list of has-many accessors. Next it calls each of those accessors, and
+displays the results in a table.
+
+#%]
+    <br /><a href="[%base%]/[%object.table%]/list">Back to listing</a>
+[% view_related(object); %]
+    
+[%
+    button(object, "edit");
+    button(object, "delete");
+%]
+[% INCLUDE footer %]
index 6f48663e45787434fd658b00ebfc863b1fd344f8..e0cdf3baeaea7db04abd8600575236b7302b6848 100644 (file)
@@ -188,7 +188,7 @@ you need to write for a simple database front-end:
         "a pub has beers on handpumps");
     1;
 
-There's a version of this program in the F<ex/> directory in the Maypole
+There's a version of this program in the F<examples/> directory in the Maypole
 files that you downloaded in the F<~root/.cpan/> build area.
 This defines the C<BeerDB> application.
 To set it up as a mod_perl handler, just tell the Apache configuration
index b7a59a2f565813c9a5c3c4a7ffaee12d845ac232..ac2aceb1b190e777e7e0200f28182f72d9890cc1 100644 (file)
@@ -7,6 +7,8 @@ use File::Spec::Functions qw(catdir tmpdir);
 our $error_template; 
 { local $/; $error_template = <DATA>; }
 
+our $VERSION = '2.11';
+
 use strict;
 
 sub template {
index 2016bb1215f2cce7b0776c1bae4fce8344de4d33..4b589edf4a31965e4e5c8a4425055bfe8146cb96 100644 (file)
@@ -18,7 +18,7 @@ form similar to L<addnew> but with the current values filled in.
 
 [% IF object %]
 <div id="title">Edit a [% classmetadata.moniker %]</div>
-<form action="[% base %]/[% item.table %]/do_edit/[% item.id %]" method="post">
+<form action="[% base %]/[% item.table %]/do_edit/[% object.id %]" method="post">
 <fieldset>
 <legend>Edit [% object.name %]</legend>
    [% FOR col = classmetadata.columns;
index ba7b83434e7feba3735a7f459e14f4c2931d51e4..848898593c889aa66978e8aec5e4ad0ed194239f 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 use Test::More;
-use lib 'ex'; # Where BeerDB should live
+use lib 'examples'; # Where BeerDB should live
 BEGIN {
     $ENV{BEERDB_DEBUG} = 0;
 
index 1efc73c252cfe12ba411d62aaf450666f25814d7..8afe8885e73f2c16f00afd3c454f56d06ea6ac56 100755 (executable)
--- a/t/crud.t
+++ b/t/crud.t
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 use Test::More;
-use lib 'ex'; # Where BeerDB should live
+use lib 'examples'; # Where BeerDB should live
 BEGIN {
     $ENV{BEERDB_DEBUG} = 2;
 
index 2b341eb699c1a6e279ce2c25b2c253c8da47c390..74dea75bee3c7b728d67ec2a01a2d855a3f8ae93 100755 (executable)
@@ -1,9 +1,9 @@
 #!/usr/bin/perl -w
 use Test::More;
 use Data::Dumper;
-use lib 'ex'; # Where BeerDB should live
+use lib 'examples'; # Where BeerDB should live
 BEGIN {
-   plan tests => 65;
+   plan tests => 45;
 }
 
 $db            = 'test';