From: Aaron Trevena Date: Thu, 10 Aug 2006 13:40:40 +0000 (+0000) Subject: moved ex to examples, fix to edit template X-Git-Tag: 2.12~54 X-Git-Url: https://git.decadent.org.uk/gitweb/?a=commitdiff_plain;h=79aa8d27d124d06bf88b2fc0487ae97563b98936;p=maypole.git moved ex to examples, fix to edit template git-svn-id: http://svn.maypole.perl.org/Maypole/trunk@520 48953598-375a-da11-a14b-00016c27c3ee --- diff --git a/Changes b/Changes index c7efd8a..c4cc7db 100644 --- 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 diff --git a/MANIFEST b/MANIFEST index d5515b9..623a934 100644 --- 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 index e0b2894..0000000 --- a/ex/BeerDB.pm +++ /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 index 75ed338..0000000 --- a/ex/BeerDB/Base.pm +++ /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 index d7de346..0000000 --- a/ex/BeerDB/Beer.pm +++ /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 index 0c6a0df..0000000 --- a/ex/beerdb.sql +++ /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 index cb72574..0000000 --- a/ex/fancy_example/BeerDB.pm +++ /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 index aaafce1..0000000 --- a/ex/fancy_example/BeerDB/Base.pm +++ /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 index d7de346..0000000 --- a/ex/fancy_example/BeerDB/Beer.pm +++ /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 index ad99483..0000000 --- a/ex/fancy_example/BeerDB/Brewery.pm +++ /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 index db798fd..0000000 --- a/ex/fancy_example/BeerDB/Drinker.pm +++ /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 index 6089c94..0000000 --- a/ex/fancy_example/beerdb.sql +++ /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 index 7053240..0000000 --- a/ex/fancy_example/templates/custom/addnew +++ /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; %] - -
-
-
-Add a new [% config.TABLES.$tbl.singular || tbl | ucfirst | replace('_',' '); %] - [% INCLUDE display_inputs; %] - - -
-
-
diff --git a/ex/fancy_example/templates/custom/display_inputs b/ex/fancy_example/templates/custom/display_inputs deleted file mode 100644 index 6baf703..0000000 --- a/ex/fancy_example/templates/custom/display_inputs +++ /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; - "

$heading

"; - 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; -%] - - - - [% IF errors.$col %] - [% errors.$col | html %] - [% END %] -[% END; %] - - - -[% 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 index 9985bfb..0000000 --- a/ex/fancy_example/templates/custom/display_search_inputs +++ /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; "
"; 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; -%] - - -[% END; %] - - diff --git a/ex/fancy_example/templates/custom/edit b/ex/fancy_example/templates/custom/edit deleted file mode 100644 index dae8c42..0000000 --- a/ex/fancy_example/templates/custom/edit +++ /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 but with the current values filled in. - -=cut - -#%] -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] - -[% IF request.action == 'edit' %] -[% INCLUDE navbar %] -[% END %] - -[% IF objects.size %] -
Edit a [% classmetadata.moniker %]
-[% FOR item = objects; %] -
-
-Edit [% item.name %] -[% FOR col = classmetadata.columns; - NEXT IF col == "id" OR col == classmetadata.table _ "_id"; - '"; - IF errors.$col; - ''; errors.$col;''; - END; - END %] - - -
- - [% END %] -[% ELSE %] - -
-
-
-Add a new [% classmetadata.moniker %] - [% FOR col = classmetadata.columns %] - [% NEXT IF col == "id" %] - - [% IF errors.$col %] - [% errors.$col | html %] - [% END %] - - [% END; %] - - -
-
-
- -[% END %] -[% INCLUDE footer %] diff --git a/ex/fancy_example/templates/custom/header b/ex/fancy_example/templates/custom/header deleted file mode 100644 index c21fff7..0000000 --- a/ex/fancy_example/templates/custom/header +++ /dev/null @@ -1,16 +0,0 @@ - - - - - [% - title || config.application_name || - "A poorly configured Maypole application" - %] - - - - - - -
diff --git a/ex/fancy_example/templates/custom/maypole.css b/ex/fancy_example/templates/custom/maypole.css deleted file mode 100644 index b13b4f1..0000000 --- a/ex/fancy_example/templates/custom/maypole.css +++ /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 index e15fb6a..0000000 --- a/ex/fancy_example/templates/custom/metadata +++ /dev/null @@ -1,5 +0,0 @@ -

Class::DBI meta info for [% classmetadata.name %]

-[% - 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 index 5d540fb..0000000 --- a/ex/fancy_example/templates/custom/search_form +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/ex/fancy_example/templates/factory/addnew b/ex/fancy_example/templates/factory/addnew deleted file mode 100644 index 2334496..0000000 --- a/ex/fancy_example/templates/factory/addnew +++ /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 - -#%] - -
-
-
-Add a new [% classmetadata.moniker %] - [% FOR col = classmetadata.columns %] - [% NEXT IF col == "id" %] - - [% IF errors.$col %] - [% errors.$col | html %] - [% END %] - - [% END; %] - - -
-
-
diff --git a/ex/fancy_example/templates/factory/edit b/ex/fancy_example/templates/factory/edit deleted file mode 100644 index cf88311..0000000 --- a/ex/fancy_example/templates/factory/edit +++ /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 but with the current values filled in. - -=cut - -#%] -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] - -[% IF request.action == 'edit' %] -[% INCLUDE navbar %] -[% END %] - -[% IF object %] -
Edit a [% classmetadata.moniker %]
-
-
-Edit [% object.name %] - [% FOR col = classmetadata.columns; - NEXT IF col == "id" OR col == classmetadata.table _ "_id"; - '"; - IF errors.$col; - ''; errors.$col;''; - END; - END %] - - -
- -[% ELSE %] - -
-
-
-Add a new [% classmetadata.moniker %] - [% FOR col = classmetadata.columns %] - [% NEXT IF col == "id" %] - - [% IF errors.$col %] - [% errors.$col | html %] - [% END %] - - [% END; %] - - -
-
-
- -[% END %] -[% INCLUDE footer %] diff --git a/ex/fancy_example/templates/factory/footer b/ex/fancy_example/templates/factory/footer deleted file mode 100644 index 1b8ae55..0000000 --- a/ex/fancy_example/templates/factory/footer +++ /dev/null @@ -1,3 +0,0 @@ -
- - diff --git a/ex/fancy_example/templates/factory/frontpage b/ex/fancy_example/templates/factory/frontpage deleted file mode 100644 index ac47269..0000000 --- a/ex/fancy_example/templates/factory/frontpage +++ /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 %] -
- [% config.application_name || "A poorly configured Maypole application" %] -
-
- -
- -[% INCLUDE maypole %] - -[% INCLUDE footer %] diff --git a/ex/fancy_example/templates/factory/header b/ex/fancy_example/templates/factory/header deleted file mode 100644 index ba0b190..0000000 --- a/ex/fancy_example/templates/factory/header +++ /dev/null @@ -1,16 +0,0 @@ - - - - - [% - title || config.application_name || - "A poorly configured Maypole application" - %] - - - - - - -
diff --git a/ex/fancy_example/templates/factory/list b/ex/fancy_example/templates/factory/list deleted file mode 100644 index 9abbc01..0000000 --- a/ex/fancy_example/templates/factory/list +++ /dev/null @@ -1,63 +0,0 @@ -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] -[% IF search %] -
Search results
-[% ELSE %] -
Listing of all [% classmetadata.plural %]
-[% END %] -[% INCLUDE navbar %] -
- - - [% FOR col = classmetadata.list_columns.list; - NEXT IF col == "id" OR col == classmetadata.table _ "_id"; - ""; - END %] - - - [% SET count = 0; - FOR item = objects; - SET count = count + 1; - ""; - display_line(item); - ""; - END %] -
"; - 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"; - "↓"; - ELSE; - "↑"; - END; - END; - ELSE; - classmetadata.colnames.$col || col FILTER ucfirst; - END; - "Actions
- -[% INCLUDE pager %] -[% INCLUDE addnew %] -[% INCLUDE search_form %] -
-[% INCLUDE footer %] diff --git a/ex/fancy_example/templates/factory/login b/ex/fancy_example/templates/factory/login deleted file mode 100644 index af08e5b..0000000 --- a/ex/fancy_example/templates/factory/login +++ /dev/null @@ -1,27 +0,0 @@ -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] -[% user_field = config.auth.user_field || "user" %] - -
You need to log in
- -
- [% IF login_error %] -
[% login_error | html %]
- [% END %] -
-
- Login - - - -
-
-
- diff --git a/ex/fancy_example/templates/factory/macros b/ex/fancy_example/templates/factory/macros deleted file mode 100644 index fc75d09..0000000 --- a/ex/fancy_example/templates/factory/macros +++ /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 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; - ''; - label | html; - ""; -END; -%] - -[%# - -=head2 maybe_link_view - -C 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 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 column by default, and magically -URLifies columns called C. 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); - ""; - IF col == "url" AND item.url; - ' '; item.url; ''; - 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; - - ""; - END; - ''; - button(item, "edit"); - button(item, "delete"); - ""; -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) %] -
-
-[% END %] -[% END %] -[%# - -=head2 view_related - -This takes an object, and looks up the C; 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; - "
"; accessor | ucfirst; "
\n"; - "
    "; - FOR thing = object.$accessor; - "
  • "; maybe_link_view(thing); "
  • \n"; - END; - "
"; - 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 %] -
[% item.$string | html %]
- [% INCLUDE navbar %] - - - - - - [% 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 method: - -#%] - - - - - [% END; %] -
[% classmetadata.colnames.$string %][% item.$string | html %]
[% classmetadata.colnames.$col || - col | ucfirst | replace('_',' '); %] - [% IF col == "url" && item.url; # Possibly too much magic. - ' '; item.url; ''; - 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 method, or returns the object's ID -if there is no C method or other stringification method defined. - -=cut - -#%] -
-[% END %] diff --git a/ex/fancy_example/templates/factory/maypole b/ex/fancy_example/templates/factory/maypole deleted file mode 100644 index 7ab2744..0000000 --- a/ex/fancy_example/templates/factory/maypole +++ /dev/null @@ -1,7 +0,0 @@ - -
 
-
 
-
 
-
 
-
 
- diff --git a/ex/fancy_example/templates/factory/maypole.css b/ex/fancy_example/templates/factory/maypole.css deleted file mode 100644 index d63be55..0000000 --- a/ex/fancy_example/templates/factory/maypole.css +++ /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 index 0c8b168..0000000 --- a/ex/fancy_example/templates/factory/navbar +++ /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 %] - diff --git a/ex/fancy_example/templates/factory/pager b/ex/fancy_example/templates/factory/pager deleted file mode 100644 index 78c89fd..0000000 --- a/ex/fancy_example/templates/factory/pager +++ /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 template argument which responds -to the L interface. - -#%] -[% -IF pager AND pager.first_page != pager.last_page; -%] -

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; - ""; num; ""; - ELSE; - SET label = num; - SET args = "?page=" _ num; - SET args = args _ "&order=" _ request.params.order - IF request.params.order; - SET args = args _ "&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; -%] -

-[% END %] diff --git a/ex/fancy_example/templates/factory/search_form b/ex/fancy_example/templates/factory/search_form deleted file mode 100644 index d10101e..0000000 --- a/ex/fancy_example/templates/factory/search_form +++ /dev/null @@ -1,22 +0,0 @@ - diff --git a/ex/fancy_example/templates/factory/search_form_recursive b/ex/fancy_example/templates/factory/search_form_recursive deleted file mode 100644 index 5d540fb..0000000 --- a/ex/fancy_example/templates/factory/search_form_recursive +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/ex/fancy_example/templates/factory/title b/ex/fancy_example/templates/factory/title deleted file mode 100644 index 401f0a3..0000000 --- a/ex/fancy_example/templates/factory/title +++ /dev/null @@ -1 +0,0 @@ - [% config.application_name %] diff --git a/ex/fancy_example/templates/factory/view b/ex/fancy_example/templates/factory/view deleted file mode 100644 index 9f06086..0000000 --- a/ex/fancy_example/templates/factory/view +++ /dev/null @@ -1,32 +0,0 @@ -[%# - -=for doc - -The C template takes some objects (usually just one) from -C and displays the object's properties in a table. - -=cut - -#%] -[% PROCESS macros %] -[% INCLUDE header %] -[% view_item(object); %] -[%# - -=for doc - -The C template also displays a list of other objects related to the first -one via C style relationships; this is done by calling the -C method - see L - to return -a list of has-many accessors. Next it calls each of those accessors, and -displays the results in a table. - -#%] -
Back to listing -[% 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 index 0000000..e0b2894 --- /dev/null +++ b/examples/BeerDB.pm @@ -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 index 0000000..75ed338 --- /dev/null +++ b/examples/BeerDB/Base.pm @@ -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 index 0000000..d7de346 --- /dev/null +++ b/examples/BeerDB/Beer.pm @@ -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 index 0000000..0c6a0df --- /dev/null +++ b/examples/beerdb.sql @@ -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 index 0000000..cb72574 --- /dev/null +++ b/examples/fancy_example/BeerDB.pm @@ -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 index 0000000..aaafce1 --- /dev/null +++ b/examples/fancy_example/BeerDB/Base.pm @@ -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 index 0000000..d7de346 --- /dev/null +++ b/examples/fancy_example/BeerDB/Beer.pm @@ -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 index 0000000..ad99483 --- /dev/null +++ b/examples/fancy_example/BeerDB/Brewery.pm @@ -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 index 0000000..db798fd --- /dev/null +++ b/examples/fancy_example/BeerDB/Drinker.pm @@ -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 index 0000000..6089c94 --- /dev/null +++ b/examples/fancy_example/beerdb.sql @@ -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 index 0000000..7053240 --- /dev/null +++ b/examples/fancy_example/templates/custom/addnew @@ -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; %] + +
+
+
+Add a new [% config.TABLES.$tbl.singular || tbl | ucfirst | replace('_',' '); %] + [% INCLUDE display_inputs; %] + + +
+
+
diff --git a/examples/fancy_example/templates/custom/display_inputs b/examples/fancy_example/templates/custom/display_inputs new file mode 100644 index 0000000..6baf703 --- /dev/null +++ b/examples/fancy_example/templates/custom/display_inputs @@ -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; + "

$heading

"; + 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; +%] + + + + [% IF errors.$col %] + [% errors.$col | html %] + [% END %] +[% END; %] + + + +[% 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 index 0000000..9985bfb --- /dev/null +++ b/examples/fancy_example/templates/custom/display_search_inputs @@ -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; "
"; 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; +%] + + +[% END; %] + + diff --git a/examples/fancy_example/templates/custom/edit b/examples/fancy_example/templates/custom/edit new file mode 100644 index 0000000..dae8c42 --- /dev/null +++ b/examples/fancy_example/templates/custom/edit @@ -0,0 +1,72 @@ +[%# + +=head1 edit + +This is the edit page. It edits the passed-in object, by displaying a +form similar to L but with the current values filled in. + +=cut + +#%] +[% PROCESS macros %] +[% INCLUDE header %] +[% INCLUDE title %] + +[% IF request.action == 'edit' %] +[% INCLUDE navbar %] +[% END %] + +[% IF objects.size %] +
Edit a [% classmetadata.moniker %]
+[% FOR item = objects; %] +
+
+Edit [% item.name %] +[% FOR col = classmetadata.columns; + NEXT IF col == "id" OR col == classmetadata.table _ "_id"; + '"; + IF errors.$col; + ''; errors.$col;''; + END; + END %] + + +
+ + [% END %] +[% ELSE %] + +
+
+
+Add a new [% classmetadata.moniker %] + [% FOR col = classmetadata.columns %] + [% NEXT IF col == "id" %] + + [% IF errors.$col %] + [% errors.$col | html %] + [% END %] + + [% END; %] + + +
+
+
+ +[% END %] +[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/custom/header b/examples/fancy_example/templates/custom/header new file mode 100644 index 0000000..c21fff7 --- /dev/null +++ b/examples/fancy_example/templates/custom/header @@ -0,0 +1,16 @@ + + + + + [% + title || config.application_name || + "A poorly configured Maypole application" + %] + + + + + + +
diff --git a/examples/fancy_example/templates/custom/maypole.css b/examples/fancy_example/templates/custom/maypole.css new file mode 100644 index 0000000..b13b4f1 --- /dev/null +++ b/examples/fancy_example/templates/custom/maypole.css @@ -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 index 0000000..e15fb6a --- /dev/null +++ b/examples/fancy_example/templates/custom/metadata @@ -0,0 +1,5 @@ +

Class::DBI meta info for [% classmetadata.name %]

+[% + 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 index 0000000..5d540fb --- /dev/null +++ b/examples/fancy_example/templates/custom/search_form @@ -0,0 +1,9 @@ + diff --git a/examples/fancy_example/templates/factory/addnew b/examples/fancy_example/templates/factory/addnew new file mode 100644 index 0000000..2334496 --- /dev/null +++ b/examples/fancy_example/templates/factory/addnew @@ -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 + +#%] + +
+
+
+Add a new [% classmetadata.moniker %] + [% FOR col = classmetadata.columns %] + [% NEXT IF col == "id" %] + + [% IF errors.$col %] + [% errors.$col | html %] + [% END %] + + [% END; %] + + +
+
+
diff --git a/examples/fancy_example/templates/factory/edit b/examples/fancy_example/templates/factory/edit new file mode 100644 index 0000000..cf88311 --- /dev/null +++ b/examples/fancy_example/templates/factory/edit @@ -0,0 +1,70 @@ +[%# + +=head1 edit + +This is the edit page. It edits the passed-in object, by displaying a +form similar to L but with the current values filled in. + +=cut + +#%] +[% PROCESS macros %] +[% INCLUDE header %] +[% INCLUDE title %] + +[% IF request.action == 'edit' %] +[% INCLUDE navbar %] +[% END %] + +[% IF object %] +
Edit a [% classmetadata.moniker %]
+
+
+Edit [% object.name %] + [% FOR col = classmetadata.columns; + NEXT IF col == "id" OR col == classmetadata.table _ "_id"; + '"; + IF errors.$col; + ''; errors.$col;''; + END; + END %] + + +
+ +[% ELSE %] + +
+
+
+Add a new [% classmetadata.moniker %] + [% FOR col = classmetadata.columns %] + [% NEXT IF col == "id" %] + + [% IF errors.$col %] + [% errors.$col | html %] + [% END %] + + [% END; %] + + +
+
+
+ +[% END %] +[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/factory/footer b/examples/fancy_example/templates/factory/footer new file mode 100644 index 0000000..1b8ae55 --- /dev/null +++ b/examples/fancy_example/templates/factory/footer @@ -0,0 +1,3 @@ +
+ + diff --git a/examples/fancy_example/templates/factory/frontpage b/examples/fancy_example/templates/factory/frontpage new file mode 100644 index 0000000..ac47269 --- /dev/null +++ b/examples/fancy_example/templates/factory/frontpage @@ -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 %] +
+ [% config.application_name || "A poorly configured Maypole application" %] +
+
+ +
+ +[% INCLUDE maypole %] + +[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/factory/header b/examples/fancy_example/templates/factory/header new file mode 100644 index 0000000..ba0b190 --- /dev/null +++ b/examples/fancy_example/templates/factory/header @@ -0,0 +1,16 @@ + + + + + [% + title || config.application_name || + "A poorly configured Maypole application" + %] + + + + + + +
diff --git a/examples/fancy_example/templates/factory/list b/examples/fancy_example/templates/factory/list new file mode 100644 index 0000000..9abbc01 --- /dev/null +++ b/examples/fancy_example/templates/factory/list @@ -0,0 +1,63 @@ +[% PROCESS macros %] +[% INCLUDE header %] +[% INCLUDE title %] +[% IF search %] +
Search results
+[% ELSE %] +
Listing of all [% classmetadata.plural %]
+[% END %] +[% INCLUDE navbar %] +
+ + + [% FOR col = classmetadata.list_columns.list; + NEXT IF col == "id" OR col == classmetadata.table _ "_id"; + ""; + END %] + + + [% SET count = 0; + FOR item = objects; + SET count = count + 1; + ""; + display_line(item); + ""; + END %] +
"; + 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"; + "↓"; + ELSE; + "↑"; + END; + END; + ELSE; + classmetadata.colnames.$col || col FILTER ucfirst; + END; + "Actions
+ +[% INCLUDE pager %] +[% INCLUDE addnew %] +[% INCLUDE search_form %] +
+[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/factory/login b/examples/fancy_example/templates/factory/login new file mode 100644 index 0000000..af08e5b --- /dev/null +++ b/examples/fancy_example/templates/factory/login @@ -0,0 +1,27 @@ +[% PROCESS macros %] +[% INCLUDE header %] +[% INCLUDE title %] +[% user_field = config.auth.user_field || "user" %] + +
You need to log in
+ +
+ [% IF login_error %] +
[% login_error | html %]
+ [% END %] +
+
+ Login + + + +
+
+
+ diff --git a/examples/fancy_example/templates/factory/macros b/examples/fancy_example/templates/factory/macros new file mode 100644 index 0000000..fc75d09 --- /dev/null +++ b/examples/fancy_example/templates/factory/macros @@ -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 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; + ''; + label | html; + ""; +END; +%] + +[%# + +=head2 maybe_link_view + +C 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 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 column by default, and magically +URLifies columns called C. 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); + ""; + IF col == "url" AND item.url; + ' '; item.url; ''; + 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; + + ""; + END; + ''; + button(item, "edit"); + button(item, "delete"); + ""; +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) %] +
+
+[% END %] +[% END %] +[%# + +=head2 view_related + +This takes an object, and looks up the C; 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; + "
"; accessor | ucfirst; "
\n"; + "
    "; + FOR thing = object.$accessor; + "
  • "; maybe_link_view(thing); "
  • \n"; + END; + "
"; + 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 %] +
[% item.$string | html %]
+ [% INCLUDE navbar %] + + + + + + [% 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 method: + +#%] + + + + + [% END; %] +
[% classmetadata.colnames.$string %][% item.$string | html %]
[% classmetadata.colnames.$col || + col | ucfirst | replace('_',' '); %] + [% IF col == "url" && item.url; # Possibly too much magic. + ' '; item.url; ''; + 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 method, or returns the object's ID +if there is no C method or other stringification method defined. + +=cut + +#%] +
+[% END %] diff --git a/examples/fancy_example/templates/factory/maypole b/examples/fancy_example/templates/factory/maypole new file mode 100644 index 0000000..7ab2744 --- /dev/null +++ b/examples/fancy_example/templates/factory/maypole @@ -0,0 +1,7 @@ + +
 
+
 
+
 
+
 
+
 
+ diff --git a/examples/fancy_example/templates/factory/maypole.css b/examples/fancy_example/templates/factory/maypole.css new file mode 100644 index 0000000..d63be55 --- /dev/null +++ b/examples/fancy_example/templates/factory/maypole.css @@ -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 index 0000000..0c8b168 --- /dev/null +++ b/examples/fancy_example/templates/factory/navbar @@ -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 %] + diff --git a/examples/fancy_example/templates/factory/pager b/examples/fancy_example/templates/factory/pager new file mode 100644 index 0000000..78c89fd --- /dev/null +++ b/examples/fancy_example/templates/factory/pager @@ -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 template argument which responds +to the L interface. + +#%] +[% +IF pager AND pager.first_page != pager.last_page; +%] +

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; + ""; num; ""; + ELSE; + SET label = num; + SET args = "?page=" _ num; + SET args = args _ "&order=" _ request.params.order + IF request.params.order; + SET args = args _ "&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; +%] +

+[% END %] diff --git a/examples/fancy_example/templates/factory/search_form b/examples/fancy_example/templates/factory/search_form new file mode 100644 index 0000000..d10101e --- /dev/null +++ b/examples/fancy_example/templates/factory/search_form @@ -0,0 +1,22 @@ + diff --git a/examples/fancy_example/templates/factory/search_form_recursive b/examples/fancy_example/templates/factory/search_form_recursive new file mode 100644 index 0000000..5d540fb --- /dev/null +++ b/examples/fancy_example/templates/factory/search_form_recursive @@ -0,0 +1,9 @@ + diff --git a/examples/fancy_example/templates/factory/title b/examples/fancy_example/templates/factory/title new file mode 100644 index 0000000..401f0a3 --- /dev/null +++ b/examples/fancy_example/templates/factory/title @@ -0,0 +1 @@ + [% config.application_name %] diff --git a/examples/fancy_example/templates/factory/view b/examples/fancy_example/templates/factory/view new file mode 100644 index 0000000..9f06086 --- /dev/null +++ b/examples/fancy_example/templates/factory/view @@ -0,0 +1,32 @@ +[%# + +=for doc + +The C template takes some objects (usually just one) from +C and displays the object's properties in a table. + +=cut + +#%] +[% PROCESS macros %] +[% INCLUDE header %] +[% view_item(object); %] +[%# + +=for doc + +The C template also displays a list of other objects related to the first +one via C style relationships; this is done by calling the +C method - see L - to return +a list of has-many accessors. Next it calls each of those accessors, and +displays the results in a table. + +#%] +
Back to listing +[% view_related(object); %] + +[% + button(object, "edit"); + button(object, "delete"); +%] +[% INCLUDE footer %] diff --git a/lib/Maypole/Manual/About.pod b/lib/Maypole/Manual/About.pod index 6f48663..e0cdf3b 100644 --- a/lib/Maypole/Manual/About.pod +++ b/lib/Maypole/Manual/About.pod @@ -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 directory in the Maypole +There's a version of this program in the F directory in the Maypole files that you downloaded in the F<~root/.cpan/> build area. This defines the C application. To set it up as a mod_perl handler, just tell the Apache configuration diff --git a/lib/Maypole/View/TT.pm b/lib/Maypole/View/TT.pm index b7a59a2..ac2aceb 100644 --- a/lib/Maypole/View/TT.pm +++ b/lib/Maypole/View/TT.pm @@ -7,6 +7,8 @@ use File::Spec::Functions qw(catdir tmpdir); our $error_template; { local $/; $error_template = ; } +our $VERSION = '2.11'; + use strict; sub template { diff --git a/lib/Maypole/templates/factory/edit b/lib/Maypole/templates/factory/edit index 2016bb1..4b589ed 100644 --- a/lib/Maypole/templates/factory/edit +++ b/lib/Maypole/templates/factory/edit @@ -18,7 +18,7 @@ form similar to L but with the current values filled in. [% IF object %]
Edit a [% classmetadata.moniker %]
-
+
Edit [% object.name %] [% FOR col = classmetadata.columns; diff --git a/t/01basics.t b/t/01basics.t index ba7b834..8488985 100644 --- a/t/01basics.t +++ b/t/01basics.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} = 0; diff --git a/t/crud.t b/t/crud.t index 1efc73c..8afe888 100755 --- 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; diff --git a/t/db_colinfo.t b/t/db_colinfo.t index 2b341eb..74dea75 100755 --- a/t/db_colinfo.t +++ b/t/db_colinfo.t @@ -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';