]> git.decadent.org.uk Git - maypole.git/commitdiff
Maypole::Application supports Maypole::HTTPD (which needs a patch).
authorDavid Baird <cpan.zerofive@googlemail.com>
Fri, 18 Nov 2005 16:41:04 +0000 (16:41 +0000)
committerDavid Baird <cpan.zerofive@googlemail.com>
Fri, 18 Nov 2005 16:41:04 +0000 (16:41 +0000)
CGI::Maypole - split collect_output() out of send_output(), for Maypole::HTTPD. Added
status attribute to request object, but only used by start_request_hook() so far. Refactored
Mp::Model::CDBI::do_edit(), for better output in Mp-Plugin-Trace.

git-svn-id: http://svn.maypole.perl.org/Maypole/trunk@427 48953598-375a-da11-a14b-00016c27c3ee

13 files changed:
Changes
lib/Apache/MVC.pm
lib/CGI/Maypole.pm
lib/Maypole.pm
lib/Maypole/Application.pm
lib/Maypole/Manual/Terminology.pod
lib/Maypole/Model/Base.pm
lib/Maypole/Model/CDBI.pm
t/03podcoverage.t
t/maypole.t
templates/factory/maypole.css [new file with mode: 0644]
templates/maypole.css [deleted file]
wishlist.txt

diff --git a/Changes b/Changes
index 8067f8a34c3fefe8800f47e79f2fe9159a65f3d7..e0b8a503858895dda31cd8a05edf2e464ea53d78 100644 (file)
--- a/Changes
+++ b/Changes
@@ -17,23 +17,29 @@ Incompatible API changes:
 
 API additions and enhancements:
     Maypole::Application:
-       -Init flag (wishlist 14123)
+       - -Init flag (wishlist 14123)
+        - recognises Maypole::HTTPD and installs Maypole::HTTPD::Frontend
+            as its frontend
     Maypole::Headers:
        add() alias to push() (wishlist 14142)
     Maypole:
-        - session() attribute, and get_session() method (no-op)
-        - user() attribute, and get_user() method (no-op)
-        - get_session() now called during handler_guts() before authenticate()
+        - get_session() method (no-op)
+        - get_user() method (no-op)
+        - get_session() is called during handler_guts() before authenticate()
         - new preprocess_path() method added and called by parse_path(), 
                parse_path() will leave any properties set by preprocess_path() in 
             place
         - start_request_hook() added
+        - status() attribute added (though only used by start_request_hook() 
+            so far)
         - setup() split into setup(), setup_model(), and load_model_subclass()
         - added new path processing methods for ssl and default table/action
         - added make_path() 
         - added make_uri()
      Templates:
         - Improved pager macro/include
+        - added the status() attribute, although it's not used in many places 
+            yet
 
 Bug fixes:
     Fix to cgi_maypole.t (bug 11346)
index 3bb33e629a549a68644819ad526f47965b367e3c..4623b9f607dbaf3c6fb2d0f47876166ed7b9d111 100644 (file)
@@ -82,7 +82,7 @@ functionality. See L<Maypole> for these:
 
 sub get_request {
     my ($self, $r) = @_;
-    my $ar = (APACHE2) ? Apache2::Request->new($r) : Apache::Request->new($r);
+    my $ar = (APACHE2) ? Apache2::Request->new($r) : Apache::Request->instance($r);
     $self->ar($ar);
 }
 
index 9b2ee7988faaf69d7f8451d06436758219094468..b8a0a48d3d40d6351f00d4533c0ca16e2953ab59 100644 (file)
@@ -7,9 +7,9 @@ use CGI::Simple;
 use Maypole::Headers;
 use Maypole::Constants;
 
-our $VERSION = '2.10';
+our $VERSION = '2.11';
 
-__PACKAGE__->mk_accessors( qw( cgi ) );
+__PACKAGE__->mk_accessors( qw/cgi/ );
 
 =head1 NAME
 
@@ -164,12 +164,28 @@ sub get_protocol
 
 =item send_output
 
+Generates output (using C<collect_output>) and prints it. 
+
 =cut
 
 sub send_output 
 {
     my $r = shift;
+    print $r->collect_output;
+}
+
+=item collect_output
+
+Gathers headers and output together into a string and returns it.
+
+Splitting this code out of C<send_output> supports L<Maypole::HTTPD::Frontend>.
 
+=cut
+
+sub collect_output
+{
+    my $r = shift;
+    
     # Collect HTTP headers
     my %headers = (
         -type            => $r->content_type,
@@ -181,7 +197,7 @@ sub send_output
         $headers{"-$_"} = $r->headers_out->get($_);
     }
 
-    print $r->cgi->header(%headers), $r->output;
+    return $r->cgi->header(%headers) . $r->output;
 }
 
 =item get_template_root
index 087f2b9daae744671f8cf3af72cd4886531edab8..dbae33be3580d65f667d6e79044ef9b30ca94634 100644 (file)
@@ -199,7 +199,7 @@ __PACKAGE__->mk_classdata($_) for qw( config init_done view_object );
 __PACKAGE__->mk_accessors(
     qw( params query objects model_class template_args output path
         args action template error document_encoding content_type table
-        headers_in headers_out stash session user)
+        headers_in headers_out stash status)
 );
 
 __PACKAGE__->config( Maypole::Config->new() );
@@ -243,6 +243,9 @@ enable/disable debugging.
 
 You can also set the C<debug> flag via L<Maypole::Application>.
 
+Some packages respond to higher debug levels, try increasing it to 2 or 3.
+
+
 =cut
 
 sub debug { 0 }      
@@ -312,10 +315,6 @@ sub setup_model
         $class->load_model_subclass($subclass);
         
         $config->model->adopt($subclass) if $config->model->can("adopt");
-
-#      eval "use $subclass"; 
-#      die "Error loading $subclass: $@"  
-#            if $@ and $@ !~ /Can\'t locate \S+ in \@INC/;
     }
 }
 
@@ -348,7 +347,7 @@ sub load_model_subclass
         (my $filename = $subclass) =~ s!::!/!g;
         die "Loading '$subclass' failed: $@\n"
                unless $@ =~ /Can\'t locate \Q$filename\E\.pm/;
-        warn "Did not find external module for '$subclass'\n
+        warn "No external module for '$subclass'
             if $class->debug > 1;
    }
 }
@@ -433,13 +432,17 @@ sub handler : method
     
     # hook useful for declining static requests e.g. images, or perhaps for 
     # sanitizing request parameters
-    my $status = $self->start_request_hook;
-    return $status unless $status == Maypole::Constants::OK();
+    $self->status(Maypole::Constants::OK());      # set the default
+    $self->__call_hook('start_request_hook');
+    return $self->status unless $self->status == Maypole::Constants::OK();
+    
+    die "status undefined after start_request_hook()" unless defined
+        $self->status;
     
-    $self->session($self->get_session);
-    $self->user($self->get_user);
+    $self->get_session;
+    $self->get_user;
     
-    $status = $self->handler_guts;
+    my $status = $self->handler_guts;
     
     # moving this here causes unit test failures - need to check why
     # before committing the move
@@ -453,6 +456,39 @@ sub handler : method
     return $status;
 }
 
+# Instead of making plugin authors use the NEXT::DISTINCT hoopla to ensure other 
+# plugins also get to call the hook, we can cycle through the application's 
+# @ISA and call them all here. Doesn't work for setup() though, because it's 
+# too ingrained in the stack. We could add a run_setup() method, but we'd break 
+# lots of existing code.
+sub __call_hook
+{
+    my ($self, $hook) = @_;
+    
+    my @plugins;
+    {
+        my $class = ref($self);
+        no strict 'refs';
+        @plugins = @{"$class\::ISA"};
+    }
+    
+    # this is either a custom method in the driver, or the method in the 1st 
+    # plugin, or the 'null' method in the frontend (i.e. inherited from 
+    # Maypole.pm) - we need to be careful to only call it once
+    my $first_hook = $self->can($hook);
+    $self->$first_hook;  
+    
+    my %seen = ( $first_hook => 1 );
+
+    # @plugins includes the frontend
+    foreach my $plugin (@plugins)
+    {
+        next unless my $plugin_hook = $plugin->can($hook);
+        next if $seen{$plugin_hook}++;
+        $self->$plugin_hook;
+    }
+}
+
 =item handler_guts
 
 This is the main request handling method and calls various methods to handle the
@@ -602,23 +638,45 @@ sub parse_location
 =item start_request_hook
 
 This is called immediately after setting up the basic request. The default
-method simply returns C<Maypole::Constants::OK>.
+method does nothing. 
 
-Any other return value causes Maypole to abort further processing of the
-request. This is useful for filtering out requests for static files, e.g.
-images, which should not be processed by Maypole or by the templating engine:
+The value of C<< $r->status >> is set to C<OK> before this hook is run. Your 
+implementation can change the status code, or leave it alone. 
+
+After this hook has run, Maypole will check the value of C<status>. For any
+value other than C<OK>, Maypole returns the C<status> immediately. 
+
+This is useful for filtering out requests for static files, e.g. images, which
+should not be processed by Maypole or by the templating engine:
 
     sub start_request_hook
     {
         my ($r) = @_;
        
-       return Maypole::Constants::DECLINED if $r->path =~ /\.jpg$/;
-       return Maypole::Constants::OK;
+        $r->status(DECLINED) if $r->path =~ /\.jpg$/;
     }
+    
+Multiple plugins, and the driver, can define this hook - Maypole will call all
+of them. You should check for and probably not change any non-OK C<status>
+value:
 
+    package Maypole::Plugin::MyApp::SkipFavicon;
+    
+    sub start_request_hook
+    {
+        my ($r) = @_;
+        
+        # check if a previous plugin has already DECLINED this request
+        # - probably unnecessary in this example, but you get the idea
+        return unless $r->status == OK;
+        
+        # then do our stuff
+        $r->status(DECLINED) if $r->path =~ /favicon\.ico/;
+    }        
+     
 =cut
 
-sub start_request_hook { Maypole::Constants::OK }
+sub start_request_hook { }
 
 =item is_applicable
 
@@ -684,7 +742,7 @@ sub is_model_applicable
     my $action = $self->action;
     return 1 if $self->model_class->is_public($action);
     
-    warn "The action '$action' is not applicable to the table $table"
+    warn "The action '$action' is not applicable to the table '$table'"
         if $self->debug;
     
     return 0;
@@ -1328,3 +1386,55 @@ You may distribute this code under the same terms as Perl itself.
 =cut
 
 1;
+
+__END__
+
+ =item register_cleanup($coderef)
+
+Analogous to L<Apache>'s C<register_cleanup>. If an Apache request object is
+available, this call simply redispatches there. If not, the cleanup is
+registered in the Maypole request, and executed when the request is
+C<DESTROY>ed.
+
+This method is only useful in persistent environments, where you need to ensure
+that some code runs when the request finishes, no matter how it finishes (e.g.
+after an unexpected error). 
+
+ =cut
+
+{
+    my @_cleanups;
+
+    sub register_cleanup
+    {
+        my ($self, $cleanup) = @_;
+        
+        die "register_cleanup() is an instance method, not a class method" 
+            unless ref $self;
+        die "Cleanup must be a coderef" unless ref($cleanup) eq 'CODE';
+        
+        if ($self->can('ar') && $self->ar)
+        {
+            $self->ar->register_cleanup($cleanup);
+        }
+        else
+        {
+            push @_cleanups, $cleanup;
+        }
+    }
+
+    sub DESTROY
+    {
+        my ($self) = @_;
+        
+        while (my $cleanup = shift @_cleanups)
+        {
+            eval { $cleanup->() };
+            if ($@)
+            {
+                warn "Error during request cleanup: $@";
+            }
+        }        
+    }    
+}
+    
index 6804cdead609ff0eb4e9c1ca8ff05df88dfec155..ae95bb7ee3447df5524c2925adbc7b193d4c0bdc 100644 (file)
@@ -2,6 +2,7 @@ package Maypole::Application;
 
 use strict;
 use warnings;
+
 use UNIVERSAL::require;
 use Maypole;
 use Maypole::Config;
@@ -15,6 +16,8 @@ sub import {
     
     my $frontend = 'Apache::MVC' if $ENV{MOD_PERL};
     
+    $frontend = 'Maypole::HTTPD::Frontend' if $ENV{MAYPOLE_HTTPD};
+    
     my $masonx;
     if ( grep { /^MasonX$/ } @plugins )
     {
@@ -30,30 +33,31 @@ sub import {
     my $autosetup=0;
     my $autoinit=0;
     my @plugin_modules;
+
+    foreach (@plugins) 
     {
-        foreach (@plugins) {
-            if    (/^\-Setup$/) { $autosetup++; }
-            elsif (/^\-Init$/)  { $autoinit++ }
-            elsif (/^\-Debug(\d*)$/) {
-                my $d = $1 || 1;
-                no strict 'refs';
-                *{"$caller\::debug"} = sub { $d };
-                warn "Debugging (level $d) enabled for $caller";
-            }
-            elsif (/^-.*$/) { warn "Unknown flag: $_" }
-            else {
-                my $plugin = "Maypole::Plugin::$_";
-                if ($plugin->require) {
-                    push @plugin_modules, "Maypole::Plugin::$_";
-                    warn "Loaded plugin: $plugin for $caller"
-                        if $caller->can('debug') && $caller->debug;
-                } else {
-                    die qq(Loading plugin "$plugin" for $caller failed: )
-                        . $UNIVERSAL::require::ERROR;
-                }
+        if    (/^\-Setup$/) { $autosetup++; }
+        elsif (/^\-Init$/)  { $autoinit++ }
+        elsif (/^\-Debug(\d*)$/) {
+            my $d = $1 || 1;
+            no strict 'refs';
+            *{"$caller\::debug"} = sub { $d };
+            warn "Debugging (level $d) enabled for $caller";
+        }
+        elsif (/^-.*$/) { warn "Unknown flag: $_" }
+        else {
+            my $plugin = "Maypole::Plugin::$_";
+            if ($plugin->require) {
+                push @plugin_modules, "Maypole::Plugin::$_";
+                warn "Loaded plugin: $plugin for $caller"
+                    if $caller->can('debug') && $caller->debug;
+            } else {
+                die qq(Loading plugin "$plugin" for $caller failed: )
+                    . $UNIVERSAL::require::ERROR;
             }
         }
     }
+    
     no strict 'refs';
     push @{"${caller}::ISA"}, @plugin_modules, $frontend;
     $caller->config(Maypole::Config->new);
index d7bf7f433e315a4d9f0827328df1e18438518517..adc5dc85b64d017782b9db0d8d78d5d0d4739c0a 100644 (file)
@@ -151,7 +151,7 @@ The functionality provided by the Maypole model class is more accurately
 described as a Presentation Model (see below). In complex Maypole applications,\r
 it is good practise to separate the domain model (the 'heart' of the\r
 application) into a separate class hierarchy (see\r
-L<Maypole::Manual::Inheritance).\r
+L<Maypole::Manual::Inheritance>).\r
 \r
 The distinction is relatively unimportant when using Maypole in 'default' mode - \r
 i.e. using L<Maypole::Model::CDBI>, and allowing Maypole to autogenerate the \r
@@ -179,6 +179,8 @@ point, the convenience of dropping new methods into the 'shared' classes will be
 outweighed by the heuristic advantage of separating different layers into\r
 separate class hierarchies.\r
 \r
+=back\r
+\r
 =head3 Presentation Model\r
 \r
 This pattern more accurately describes the role of the Maypole model.\r
@@ -196,8 +198,6 @@ queries the Presentation Model to retrieve these new values. In Maypole, this is
 the role of the C<vars()> method on L<Maypole::View::Base>, which transmits the\r
 new values to the templates.\r
 \r
-=back\r
-\r
 =head1 AUTHOR\r
 \r
 David Baird, C<< <cpan@riverside-cms.co.uk> >>\r
index 26288c29f15cd32d4d00a0dd117ba215cbc1c333..338f0e8a85449808cc5e9954a581cd5dceaa9c29 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use Maypole::Constants;
 use attributes ();
 
+# don't know why this is a global - drb
 our %remember;
 
 sub MODIFY_CODE_ATTRIBUTES 
@@ -28,6 +29,7 @@ sub process {
     $r->{template} = $method;
     my $obj = $class->fetch_objects($r);
     $r->objects([$obj]) if $obj;
+    
     $class->$method( $r, $obj, @{ $r->{args} } );
 }
 
@@ -195,7 +197,7 @@ sub is_public
     
     return 1 if $attrs{Exported};
     
-    warn "$action not exported" if Maypole->debug;
+    warn "'$action' not exported";
     
     return 0;
 }
index df8d6c8b210094f3bc23703ae8e0a1f8bc522248..6ae19f53fa12db0ee355dcebb6425e26b30fe256 100644 (file)
@@ -105,48 +105,70 @@ sub related_class {
  }
 
 
-sub do_edit : Exported {
-    my ( $self, $r ) = @_;
-    my $h        = CGI::Untaint->new( %{ $r->{params} } );
-    my $creating = 0;
-    my ($obj) = @{ $r->objects || [] };
+sub do_edit : Exported 
+{
+    my ($self, $r, $obj) = @_;
+
+    my $config   = $r->config;
+    my $table    = $r->table;
+    
+    my $required_cols = $config->{$table}->{required_cols} || [];
+    
+    ($obj, my $fatal, my $creating) = $self->_do_update_or_create($r, $obj, $required_cols);
+    
+    # handle errors, if none, proceed to view the newly created/updated object
+    my %errors = $fatal ? (FATAL => $fatal) : $obj->cgi_update_errors;
+    
+    if (%errors) 
+    {
+        # Set it up as it was:
+        $r->template_args->{cgi_params} = $r->params;
+        $r->template_args->{errors}     = \%errors;
+
+        undef $obj if $creating;
+        $r->template("edit");
+    }
+    else 
+    {
+        $r->template("view");
+    }
+    
+    $r->objects( $obj ? [$obj] : []);
+}
+
+# drb - I've (probably temporarily) split this out from do_edit, so it's 
+# reported by Mp::P::Trace
+sub _do_update_or_create
+{
+    my ($self, $r, $obj, $required_cols) = @_;
+    
     my $fatal;
-    if ($obj) {
+    my $creating = 0;
+    my $h = CGI::Untaint->new( %{$r->params} );
+    
+    # update or create
+    if ($obj) 
+    {
         # We have something to edit
-        eval {
-            $obj->update_from_cgi( $h =>
-                { required => $r->{config}{ $r->{table} }{required_cols} || [], }
-            );
-        };
+        eval { $obj->update_from_cgi( $h => {required => $required_cols} ) };
         $fatal = $@;
     }
-    else {
-        eval {
-            $obj =
-                $self->create_from_cgi( $h =>
-                    { required => $r->{config}{ $r->{table} }{required_cols} || [], }
-            );
+    else 
+    {
+        eval { 
+            $obj = $self->create_from_cgi( $h => {required => $required_cols} ) 
         };
-        if ($fatal = $@) {
+        
+        if ($fatal = $@) 
+        {
             warn "$fatal" if $r->debug;
         }
         $creating++;
     }
-    if ( my %errors = $fatal ? (FATAL => $fatal) : $obj->cgi_update_errors ) {
-
-        # Set it up as it was:
-        $r->{template_args}{cgi_params} = $r->{params};
-        $r->{template_args}{errors}     = \%errors;
-
-        undef $obj if $creating;
-        $r->template("edit");
-    }
-    else {
-        $r->{template} = "view";
-    }
-    $r->objects( $obj ? [$obj] : []);
+    
+    return $obj, $fatal, $creating;
 }
-
+    
 sub delete : Exported {
     return shift->SUPER::delete(@_) if caller ne "Maypole::Model::Base";
     my ( $self, $r ) = @_;
index d8d403de77c31bb16452f439866ccb42563db401..fa45ce2fbe681c2175cb95106ae8b3af866be0e7 100644 (file)
@@ -4,6 +4,6 @@ use strict;
 use Test::More;
 
 eval "use Test::Pod::Coverage 1.04";
-plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@;
+plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage ($@)" if $@;
 all_pod_coverage_ok({  also_private => [ qr/^[A-Z_]+$/ ], });
 
index 4a0cd0234fec89e718f0ed2c0ad24eff1d885383..9e49186fe884a1004903131049d120900a8e4e73 100755 (executable)
@@ -32,7 +32,8 @@ my @API = qw/ config init_done view_object params query param objects model_clas
               make_uri get_template_root get_request
               parse_location send_output
              start_request_hook
-             session get_session
+             get_session
+          get_user
               /;
                 
 can_ok(Maypole => @API);
diff --git a/templates/factory/maypole.css b/templates/factory/maypole.css
new file mode 100644 (file)
index 0000000..51d99a4
--- /dev/null
@@ -0,0 +1,376 @@
+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 .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/templates/maypole.css b/templates/maypole.css
deleted file mode 100644 (file)
index 51d99a4..0000000
+++ /dev/null
@@ -1,376 +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 .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;
-}
-
index 7ee5bfbb76034566236441a483c9573736a0d972..1ce65b5ba7860562d03fb8e38e5472f5670441c9 100644 (file)
@@ -12,7 +12,7 @@ Fix bug 14570 - returning error codes breaks CGI::Maypole
 Write Maypole::Manual::Exceptions\r
 Test and refactor external_redirect()\r
 \r
-Fix Mp::P::USC\r
+Fix Mp::P::USC\r
 \r
 2.12\r
 ====\r
@@ -25,7 +25,9 @@ Handle repeat form submissions.
 Implement internal_redirect().\r
 Build a more sophisticated app for testing. \r
 Move class_of() to the controller - need to do this to support multiple models. \r
-Multiple model support.\r
+Multiple model support - URLs like /$base/$model/$table/$action/$id.\r
+Refactor M-P-USC and M-P-Session into M-P-User, M-P-Session, and M-P-Cookie\r
+\r
 \r
 3.0\r
 ====\r