[Jifty-commit] r3593 - in jifty/branches/virtual-models: . debian doc/talks lib/Jifty lib/Jifty/Manual lib/Jifty/Plugin lib/Jifty/Plugin/Authentication lib/Jifty/Plugin/Authentication/Password lib/Jifty/Plugin/Authentication/Password/Mixin/Model lib/Jifty/Plugin/CompressedCSSandJS lib/Jifty/Plugin/Debug lib/Jifty/Plugin/ErrorTemplates lib/Jifty/Plugin/Feedback lib/Jifty/Plugin/OpenID lib/Jifty/Plugin/OpenID/Action lib/Jifty/Plugin/OpenID/Mixin/Model lib/Jifty/Plugin/SinglePage lib/Jifty/Plugin/SiteNews lib/Jifty/Plugin/SiteNews/View lib/Jifty/Plugin/SkeletonApp lib/Jifty/Plugin/User/Mixin/Model lib/Jifty/Request lib/Jifty/View lib/Jifty/View/Declare lib/Jifty/View/Mason lib/Jifty/View/Static lib/Jifty/Web lib/Jifty/Web/Form share/web/static/js share/web/static/js/yui t/Mapper/lib/Mapper/Action t/Mapper/t t/TestApp/lib/TestApp t/TestApp/share/web/templates/dispatch t/TestApp/t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sun Jul 1 23:56:38 EDT 2007


Author: sterling
Date: Sun Jul  1 23:56:36 2007
New Revision: 3593

Added:
   jifty/branches/virtual-models/lib/Jifty/Plugin/Debug/
   jifty/branches/virtual-models/lib/Jifty/Plugin/Debug.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Debug/Dispatcher.pm
   jifty/branches/virtual-models/share/web/static/js/yui/oom_select.patch
   jifty/branches/virtual-models/t/TestApp/share/web/templates/dispatch/protocol
   jifty/branches/virtual-models/t/TestApp/t/02-dispatch-http.t
   jifty/branches/virtual-models/t/TestApp/t/02-dispatch-https.t
Removed:
   jifty/branches/virtual-models/doc/talks/
Modified:
   jifty/branches/virtual-models/   (props changed)
   jifty/branches/virtual-models/Makefile.PL
   jifty/branches/virtual-models/debian/control
   jifty/branches/virtual-models/lib/Jifty/Action.pm
   jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm
   jifty/branches/virtual-models/lib/Jifty/Config.pm
   jifty/branches/virtual-models/lib/Jifty/CurrentUser.pm
   jifty/branches/virtual-models/lib/Jifty/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Manual/Continuations.pod
   jifty/branches/virtual-models/lib/Jifty/Manual/Cookbook.pod
   jifty/branches/virtual-models/lib/Jifty/Plugin.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/View.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/ErrorTemplates/View.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/Feedback/View.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Action/CreateOpenIDUser.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/View.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/View/News.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/SkeletonApp/View.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/User.pm
   jifty/branches/virtual-models/lib/Jifty/Plugin/User/Mixin/Model/User.pm
   jifty/branches/virtual-models/lib/Jifty/Request.pm
   jifty/branches/virtual-models/lib/Jifty/Request/Mapper.pm
   jifty/branches/virtual-models/lib/Jifty/Test.pm
   jifty/branches/virtual-models/lib/Jifty/Upgrade.pm
   jifty/branches/virtual-models/lib/Jifty/View.pm
   jifty/branches/virtual-models/lib/Jifty/View/Declare.pm
   jifty/branches/virtual-models/lib/Jifty/View/Declare/BaseClass.pm
   jifty/branches/virtual-models/lib/Jifty/View/Declare/CRUD.pm
   jifty/branches/virtual-models/lib/Jifty/View/Declare/Helpers.pm
   jifty/branches/virtual-models/lib/Jifty/View/Declare/Page.pm
   jifty/branches/virtual-models/lib/Jifty/View/Mason/Handler.pm
   jifty/branches/virtual-models/lib/Jifty/View/Static/Handler.pm
   jifty/branches/virtual-models/lib/Jifty/Web.pm
   jifty/branches/virtual-models/lib/Jifty/Web/Form.pm
   jifty/branches/virtual-models/lib/Jifty/Web/Form/Element.pm
   jifty/branches/virtual-models/lib/Jifty/Web/Form/Link.pm
   jifty/branches/virtual-models/lib/Jifty/Web/Session.pm
   jifty/branches/virtual-models/share/web/static/js/jifty.js
   jifty/branches/virtual-models/share/web/static/js/yui/calendar.js
   jifty/branches/virtual-models/t/Mapper/lib/Mapper/Action/CrossBridge.pm
   jifty/branches/virtual-models/t/Mapper/share/web/templates/index.html
   jifty/branches/virtual-models/t/Mapper/t/02-api.t
   jifty/branches/virtual-models/t/TestApp/lib/TestApp/Dispatcher.pm

Log:
 r7912 at dynpc145:  andrew | 2007-07-01 20:35:13 -0500
 Merging latest trunk into virtual-models. No new tests fail.


Modified: jifty/branches/virtual-models/Makefile.PL
==============================================================================
--- jifty/branches/virtual-models/Makefile.PL	(original)
+++ jifty/branches/virtual-models/Makefile.PL	Sun Jul  1 23:56:36 2007
@@ -65,6 +65,7 @@
 requires('SVN::Repos');
 requires('SVN::Simple::Edit');
 requires('Template::Declare' => '0.07');                # Template::Declare::Tags
+requires('Template::Declare' => '0.21');                # Template::Declare::Tags
 requires('Test::Base');
 requires('Test::LongString');
 requires('Test::More' => 0.62 ),
@@ -138,7 +139,7 @@
         recommends('LWPx::ParanoidAgent'),
     ],
     'Jifty console' => [
-        -default => 1,
+        -default => 0,
         recommends('Devel::EvalContext')
     ],
 );

Modified: jifty/branches/virtual-models/debian/control
==============================================================================
--- jifty/branches/virtual-models/debian/control	(original)
+++ jifty/branches/virtual-models/debian/control	Sun Jul  1 23:56:36 2007
@@ -66,14 +66,14 @@
  libhtml-lint-perl, libhtml-mason-perl (>> 1.31), 
  libwww-perl, libhttp-server-simple-perl (>> 0.26), 
  libhttp-server-simple-recorder-perl, libhash-merge-perl, libhook-lexwrap-perl,
- libipc-pubsub-perl (>> 0.23), libjifty-dbi-perl (>> 0.40),
+ libipc-pubsub-perl (>> 0.23), libjifty-dbi-perl (>> 0.40), libipc-run3-perl,
  liblocale-maketext-lexicon-perl, liblocale-maketext-simple-perl, liblog-log4perl-perl,
  libmime-types-perl, libmodule-pluggable-perl (>> 3.5),
  libmodule-corelist-perl, libmodule-refresh-perl,
  libmodule-scandeps-perl, libobject-declare-perl (>> 0.22),
  libparams-validate-perl, libscalar-defer-perl (>> 0.10),
  libstring-koremutake-perl, libsql-reservedwords-perl,
- libtemplate-declare-perl (>> 0.07), 
+ libtemplate-declare-perl (>> 0.21), 
  libtest-base-perl, libuniversal-require-perl, liburi-perl,
  libxml-writer-perl (>> 0.601), libxml-simple-perl,
  libxml-xpath-perl, libversion-perl, libyaml-syck-perl (>> 0.72), 

Modified: jifty/branches/virtual-models/lib/Jifty/Action.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Action.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Action.pm	Sun Jul  1 23:56:36 2007
@@ -36,7 +36,7 @@
 See also L<Jifty::Action::Record> for data-oriented actions, 
 L<Jifty::Result> for how to return values from actions.
 
-See L<Jifty::Param::Schema> for more details on the declarative 
+See L<Jifty::Param::Schema> for more details on the declarative
 syntax.
 
 See L<Jifty::Manual::Actions> for examples of using actions.
@@ -57,7 +57,8 @@
 
 B<Do not call this directly>; always go through C<< Jifty->web->new_action >>! 
 
-This method constructs a new action. Subclasses who need do custom initialization should start with:
+This method constructs a new action. Subclasses who need do custom
+initialization should start with:
 
     my $class = shift;
     my $self = $class->SUPER::new(@_)
@@ -81,29 +82,20 @@
 =item arguments
 
 A hash reference of default values for the
-L<arguments|Jifty::Manual::Glossary/argument> of the action.  Defaults to
-none.
+L<arguments|Jifty::Manual::Glossary/argument> of the action.  Defaults
+to none.
 
 =item sticky_on_failure
 
 A boolean value that determines if the form fields are
-L<sticky|Jifty::Manual::Glossary/sticky> when the action fails.  Defaults to
-true.
+L<sticky|Jifty::Manual::Glossary/sticky> when the action fails.
+Defaults to true.
 
 =item sticky_on_success
 
 A boolean value that determines if the form fields are
-L<sticky|Jifty::Manual::Glossary/sticky> when the action succeeds.  Defaults
-to false.
-
-=begin private
-
-=item request_arguments
-
-A hashref of arguments passed in as part of the
-L<Jifty::Request>. Internal use only.
-
-=end private
+L<sticky|Jifty::Manual::Glossary/sticky> when the action succeeds.
+Defaults to false.
 
 =back
 
@@ -127,13 +119,16 @@
         $self->_get_current_user();
     }
 
-    if ($args{'moniker'}) {
-        $self->moniker($args{'moniker'});
-    } else {
-        $self->moniker($self->_generate_moniker);
-    }
+    $self->moniker($args{'moniker'} || $self->_generate_moniker);
     $self->order($args{'order'});
 
+    my $action_in_request = Jifty->web->request->action( $self->moniker );
+    # Fields explicitly passed to new_action take precedence over those passed
+    # from the request; we read from the request to implement "sticky fields".
+    if ( $action_in_request and $action_in_request->arguments ) {
+        $args{'request_arguments'} = $action_in_request->arguments;
+    }
+
     $self->argument_values( { %{ $args{'request_arguments' } }, %{ $args{'arguments'} } } );
 
     # Keep track of whether arguments came from the request, or were
@@ -153,11 +148,12 @@
 
 =head2 _generate_moniker 
 
-Construct a moniker for a new (or soon-to-be-constructed) action that did not have
-an explicit moniker specified.  The algorithm is simple: We snapshot the call stack,
-prefix it with the action class, and then append it with an per-request autoincrement
-counter in case the same class/stack is encountered twice, which can happen if the
-programmer placed a C<new_action> call inside a loop.
+Construct a moniker for a new (or soon-to-be-constructed) action that
+did not have an explicit moniker specified.  The algorithm is simple:
+We snapshot the call stack, prefix it with the action class, and then
+append it with an per-request autoincrement counter in case the same
+class/stack is encountered twice, which can happen if the programmer
+placed a C<new_action> call inside a loop.
 
 Monikers generated this way are guaranteed to work across requests.
 
@@ -1135,9 +1131,13 @@
 
 =head2 Canonicalization
 
-If you wish to have the data in a field normalized into a particular format (such as changing a date into YYYY-MM-DD format, adding commas to numbers, capitalizing words, or whatever you need) you can do so using a canonicalizer. 
+If you wish to have the data in a field normalized into a particular
+format (such as changing a date into YYYY-MM-DD format, adding commas
+to numbers, capitalizing words, or whatever you need) you can do so
+using a canonicalizer.
 
-This is just a method titled C<canonicalize_FIELD> where C<FIELD> is the name of the field be normalized. Here is an example:
+This is just a method titled C<canonicalize_FIELD> where C<FIELD> is
+the name of the field be normalized. Here is an example:
 
   sub canonicalize_foo {
       my ($self, $value) = @_;
@@ -1148,21 +1148,28 @@
       return $normal_form;
   }
 
-In this case, all values in the "foo" field will be changed into lower case.
+In this case, all values in the "foo" field will be changed into lower
+case.
 
-While doing this you might also want to call the L</canonicalization_note> to inform the client of the modification:
+While doing this you might also want to call the
+L</canonicalization_note> to inform the client of the modification:
 
   my $normal_form = lc($value);
   $self->canonicalization_note( 
       foo => _('Foo values are always in lowercase.'));
 
-If the "foo" field has "ajax canoncalizes" set in the action schema, then this process will be performed automatically as the form is being filled without reloading the page.
+If the "foo" field has "ajax canoncalizes" set in the action schema,
+then this process will be performed automatically as the form is being
+filled without reloading the page.
 
 =head2 Validation
 
-If a value must follow a certain format, you can provide a validation method for fields to make sure that no value enters the database until it is in a valid form.
+If a value must follow a certain format, you can provide a validation
+method for fields to make sure that no value enters the database until
+it is in a valid form.
 
-A validation method is one named C<validate_FIELD> where C<FIELD> is the name of the field being checked. Here is an example:
+A validation method is one named C<validate_FIELD> where C<FIELD> is
+the name of the field being checked. Here is an example:
 
   sub validate_foo {
       my ($self, $value) = @_;
@@ -1182,15 +1189,26 @@
       return 1;
   }
 
-Here the "foo" field should not contain uppercase letters and must not contain the characters '-', '*', '+', or '?'. You can use L</validation_error> and L</validation_warning> to return the results of your validation to the user or simply return 1 to indicate a valid value.
+Here the "foo" field should not contain uppercase letters and must not
+contain the characters '-', '*', '+', or '?'. You can use
+L</validation_error> and L</validation_warning> to return the results
+of your validation to the user or simply return 1 to indicate a valid
+value.
 
-If you just have a list of valid values, you may want to use the C<valid_values> schema parameter to perform this task instead.
+If you just have a list of valid values, you may want to use the
+C<valid_values> schema parameter to perform this task instead.
 
 =head2 Autocompletion
 
-Autocompletion provides a way of suggesting choices to the client based upon partial data entry. This doesn't necessarily force the client to use one of the choices given but gives hints in an application specific way.
-
-To create an autocompletion field, you implement a method named C<autocomplete_FIELD> where C<FIELD> is the field to autocomplete. This is generally done with fields rendered as 'Text'. Here is an example:
+Autocompletion provides a way of suggesting choices to the client
+based upon partial data entry. This doesn't necessarily force the
+client to use one of the choices given but gives hints in an
+application specific way.
+
+To create an autocompletion field, you implement a method named
+C<autocomplete_FIELD> where C<FIELD> is the field to
+autocomplete. This is generally done with fields rendered as
+'Text'. Here is an example:
 
   sub autocomplete_foo {
       my ($self, $value) = @_;
@@ -1209,16 +1227,25 @@
       return map { $_->name } @{ $foos->items_array_ref };
   }
 
-In this example, the "foo" field is autocompleted from names matched from the C<MyApp::Model::Foo> table. The match, in this case, matches any substring found in the database. I could have matched any item that starts with the string, ends with the string, matches other fields than the one returned, etc. It's up to you to decide.
-
-Note also that I have untainted the value coming in to make sure a malicious user doesn't get anyway. You should always perform a check like this when data is coming in from an outside source.
-
-If you need a more complicated solution, you can return the autocompletion values as a list of hash references containing the keys C<value> and (optionally) C<label>:
+In this example, the "foo" field is autocompleted from names matched
+from the C<MyApp::Model::Foo> table. The match, in this case, matches
+any substring found in the database. I could have matched any item
+that starts with the string, ends with the string, matches other
+fields than the one returned, etc. It's up to you to decide.
+
+Note also that I have untainted the value coming in to make sure a
+malicious user doesn't get anyway. You should always perform a check
+like this when data is coming in from an outside source.
+
+If you need a more complicated solution, you can return the
+autocompletion values as a list of hash references containing the keys
+C<value> and (optionally) C<label>:
 
   return map { { value => $_->name, label => $_->label } }
             @{ $foos->items_array_ref };
 
-In this case, the labels will be shown to the client, but the selected value would be returned to your application.
+In this case, the labels will be shown to the client, but the selected
+value would be returned to your application.
 
 =cut
 
@@ -1226,7 +1253,8 @@
 
 =head1 SEE ALSO
 
-L<Jifty>, L<Jifty::API>, L<Jifty::Action::Record>, L<Jifty::Result>, L<Jifty::Param::Schema>, L<Jifty::Manual::Actions>
+L<Jifty>, L<Jifty::API>, L<Jifty::Action::Record>, L<Jifty::Result>,
+L<Jifty::Param::Schema>, L<Jifty::Manual::Actions>
 
 =head1 LICENSE
 

Modified: jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm	Sun Jul  1 23:56:36 2007
@@ -141,7 +141,7 @@
                   "package $module;\n"
                 . "use base qw/Jifty::CurrentUser/; sub _autogenerated { 1 };\n"
             );
-    } elsif ( $module =~ /^(?:$base)::Model::(\w+)Collection$/ ) {
+    } elsif ( $module =~ /^(?:$base)::Model::([^\.]+)Collection$/ ) {
         return $self->return_class(
                   "package $module;\n"
                 . "use base qw/@{[$base]}::Collection/;\n"

Modified: jifty/branches/virtual-models/lib/Jifty/Config.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Config.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Config.pm	Sun Jul  1 23:56:36 2007
@@ -366,6 +366,7 @@
             Web => {
                 DefaultStaticRoot => Jifty::Util->share_root . '/web/static',
                 DefaultTemplateRoot => Jifty::Util->share_root . '/web/templates',
+                SessionCookieName => 'JIFTY_SID_$PORT',
             },
         }
     };

Modified: jifty/branches/virtual-models/lib/Jifty/CurrentUser.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/CurrentUser.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/CurrentUser.pm	Sun Jul  1 23:56:36 2007
@@ -4,8 +4,9 @@
 package Jifty::CurrentUser;
 
 use base qw/Jifty::Object Class::Accessor::Fast/;
+use Scalar::Util qw();
 
-__PACKAGE__->mk_accessors(qw(is_superuser is_bootstrap_user user_object));
+__PACKAGE__->mk_accessors(qw(is_superuser is_bootstrap_user));
 
 
 =head1 NAME
@@ -98,6 +99,20 @@
 
 =cut
 
+sub user_object {
+    my $self = shift;
+    return $self->{'user_object'} unless @_;
+
+    $self->{'user_object'} = shift;
+    # protect ourself from circular refereces
+    if ( $self->{'user_object'}{'_current_user'} == $self ) {
+        Scalar::Util::weaken( $self->{'user_object'}{'_current_user'} )
+            unless Scalar::Util::isweak( $self->{'user_object'}{'_current_user'} );
+        $self->{'user_object'}{'_resurrect_current_user'} = 1;
+    }
+    return $self->{'user_object'};
+}
+
 =head2 id
 
 Returns C<0> if we don't have a L<user_object>.  When we I<do> have a

Modified: jifty/branches/virtual-models/lib/Jifty/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -160,7 +160,7 @@
 All wildcards in the C<$match> string becomes capturing regex patterns.  You
 can also pass in an array reference of matches, or a regex pattern.
 
-The C<$match> string may be qualified with a HTTP method name, such as
+The C<$match> string may be qualified with a HTTP method name or protocol, such as
 
 =over
 
@@ -176,6 +176,10 @@
 
 =item HEAD
 
+=item HTTPS
+
+=item HTTP
+
 =back
 
 =head2 on $match => $rule
@@ -263,6 +267,8 @@
 
     GET POST PUT HEAD DELETE OPTIONS
 
+    HTTPS HTTP
+
     plugin
 
     get next_rule last_rule
@@ -300,6 +306,9 @@
 sub DELETE ($)  { _qualify method => @_ }
 sub OPTIONS ($) { _qualify method => @_ }
 
+sub HTTPS ($)   { _qualify https  => @_ }
+sub HTTP ($)    { _qualify http   => @_ }
+
 sub plugin ($) { return { plugin => @_ } }
 
 our $CURRENT_STAGE;
@@ -929,6 +938,30 @@
     lc( $ENV{REQUEST_METHOD} ) eq lc($method);
 }
 
+=head2 _match_https
+
+Returns true if the current request is under SSL.
+
+=cut
+
+sub _match_https {
+    my $self = shift;
+    $self->log->debug("Matching request against HTTPS");
+    return exists $ENV{HTTPS} ? 1 : 0;
+}
+
+=head2 _match_http
+
+Returns true if the current request is not under SSL.
+
+=cut
+
+sub _match_http {
+    my $self = shift;
+    $self->log->debug("Matching request against HTTP");
+    return exists $ENV{HTTPS} ? 0 : 1;
+}
+
 sub _match_plugin {
     my ( $self, $plugin ) = @_;
     warn "Deferred check shouldn't happen";

Modified: jifty/branches/virtual-models/lib/Jifty/Manual/Continuations.pod
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Manual/Continuations.pod	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Manual/Continuations.pod	Sun Jul  1 23:56:36 2007
@@ -167,7 +167,7 @@
 successful, calls the stored continuation, or, lacking one, redirects
 to C</protected>.
 
-As currently impelented, these redirect-from-dispatcher tangents works
+As currently implemented, these redirect-from-dispatcher tangents works
 exactly like rendered-as-links tangents, in that when they return,
 I<all> rules in the dispatcher are still executed from the start.
 Therefore the C<unless> guard in the C<before '/protected'> rule above

Modified: jifty/branches/virtual-models/lib/Jifty/Manual/Cookbook.pod
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Manual/Cookbook.pod	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Manual/Cookbook.pod	Sun Jul  1 23:56:36 2007
@@ -400,6 +400,62 @@
         Jifty->web->out($image);
     };
 
+=head2 Create a many-to-many relationship
+
+You need to create two one-to-many relationships with a linking table as you normally would in pure SQL. First, create your linking table by running:
+
+  bin/jifty model --name LinkTable
+
+Modify the newly created C<MyApp::Model::LinkTable> class to add new columns linking back to either side of the table:
+
+  use MyApp::Record schema {
+      column left_table =>
+          refers_to MyApp::Model::LeftTable;
+      column right_table =>
+          refers_to MyApp::Model::RightTable;
+  };
+
+Then create links to the linking table in C<MyApp::Model::LeftTable>:
+
+  use MyApp::Record schema {
+      # other columns...
+      
+      column right_things =>
+          refers_to MyApp::Model::LinkTableCollection by 'left_table';
+  };
+
+Then create links to the linking table in C<MyApp::Model::RightTable>:
+
+  use MyApp::Record schema {
+      # other columns...
+      
+      column left_things =>
+          refers_to MyApp::Model::LinkTableCollection by 'right_table';
+  };
+
+Now, add your records. To create a relationship between a row the two tables:
+
+  my $left = MyApp::Model::LeftTable->new;
+  $left->load(1);
+
+  my $right = MyApp::Model::RightTable->new;
+  $right->laod(1);
+
+  my $link = MyApp::Model::LinkTable->new;
+  $link->create(
+      left_table  => $left,
+      right_table => $right,
+  );
+
+And to get all the "right things" from the left table, you need to make the extra hop in your loop:
+
+  my $links = $left->right_things;
+  while (my $link = $links->next) {
+      my $right = $link->right_table;
+  
+      # Do stuff with $right
+  }
+
 =for comment
 Document how to do this with Mason
 

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin.pm	Sun Jul  1 23:56:36 2007
@@ -98,8 +98,7 @@
         eval { $self->{share} = module_dir($class) };
     }
     unless ( $self->{share} ) {
-        local $@; # We're just avoiding File::ShareDir's failure behaviour of dying
-        eval { $self->{share} = module_dir('Jifty') };
+        $self->{share} = Jifty::Util->share_root;
         if ( $self->{'share'} ) {
             my $class_to_path = $class;
             $class_to_path =~ s|::|/|g;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password.pm	Sun Jul  1 23:56:36 2007
@@ -4,23 +4,17 @@
 package Jifty::Plugin::Authentication::Password;
 use base qw/Jifty::Plugin/;
 
-# Your plugin goes here.  If takes any configuration or arguments, you
-# probably want to override L<Jifty::Plugin/init>.
-
 =head1 NAME
 
-Jifty::Plugin::Authentication::Password
+Jifty::Plugin::Authentication::Password - password authentication plugin
 
 =head1 DESCRIPTION
 
-When finished, this plugin will provide password authentication for 
-your Jifty application. (It adds a "password" column to your "User" model class).
-
-Right now, it's useless and should be ignored.
+B<CAUTION:> This plugin is experimental.
 
+This may be combined with the L<Jifty::Plugin::User> and L<Jifty::Plugin::LetMe> plugins to provide user accounts and form-based password authentication to your application.
 
-=cut
-
+=head2 METHODS
 
 =head2 prereq_plugins
 
@@ -33,4 +27,15 @@
     return ('User', 'LetMe');
 }
 
+=head1 SEE ALSO
+
+L<Jifty::Manual::AccessControl>, L<Jifty::Plugin::User>, L<Jifty::Plugin::LetMe>, L<Jifty::Plugin::Authentication::Password::Mixin::Model::User>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
+
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -4,25 +4,22 @@
 package Jifty::Plugin::Authentication::Password::Dispatcher;
 use Jifty::Dispatcher -base;
 
-# Put any plugin-specific dispatcher rules here.
-
-
 =head1 NAME
 
-Jifty::Plugin::Authentication::Password::Dispatcher
+Jifty::Plugin::Authentication::Password::Dispatcher - password plugin dispatcher
 
 =head1 DESCRIPTION
 
 All the dispatcher rules jifty needs to support L<Jifty::Authentication::Password/>
 
-=cut
-
-
 =head1 RULES
 
-
 =head2 before logout
 
+Logout and return home.
+
+See L<Jifty::Plugin::Authentication::Password::Action::Logout>.
+
 =cut
 
 before 'logout' => run {
@@ -35,6 +32,8 @@
 
 =head2 before *
 
+Setup the navigation menu for login or logout.
+
 =cut
 
 before '*' =>  run {
@@ -47,7 +46,11 @@
 
 };
 
-=head2 on qr/^(?:passwordreminder|signup)$/ 
+=head2 on qr/^(?:passwordreminder|signup|lost_password)$/ 
+
+Redirect to home if logged.
+
+Request a password reminder or signup for an account otherwise.
 
 =cut
 
@@ -58,6 +61,10 @@
 
 =head2 on login
 
+Redirect to home if logged.
+
+Show the login form otherwise.
+
 =cut
 
 before qr|^/(?:login)$| => run {
@@ -65,12 +72,22 @@
     set 'next' => Jifty->web->request->continuation || Jifty::Continuation->new( request => Jifty::Request->new( path => "/" ) );
 };
 
+=head2 before reset_lost_password
+
+Request a password reset.
+
+=cut
+
 before qr|(?:reset_lost_password)| => run {
     set 'next' => Jifty->web->request->continuation || Jifty::Continuation->new( request => Jifty::Request->new( path => "/" ) );
 };
 # Send a password reminder for a lost password
 
-=head2 on passwordreminder
+=head2 before passwordreminder
+
+Request a new password reminder to be sent by email.
+
+See L<Jifty::Plugin::Authentication::Password::Action::SendPasswordReminder>.
 
 =cut
 
@@ -79,9 +96,11 @@
 };
 
 
-=head2 on signup
+=head2 before signup
 
-# Sign up for an account
+Sign up for an account.
+
+See L<Jifty::Plugin::Authentication::Password::Action::Signup>.
 
 =cut
 
@@ -90,9 +109,11 @@
 
 };
 
-=head2 on login
+=head2 before login
+
+Login to your account.
 
-Login
+See L<Jifty::Plugin::Authentication::Password::Action::Login>.
 
 =cut
 
@@ -102,6 +123,8 @@
 
 =head2 not_logged_in_nav
 
+Adds the login and signup links to the navigation menu.
+
 =cut
 
 sub not_logged_in_nav {
@@ -119,6 +142,8 @@
 
 =head2 logged_in_nav
 
+Adds the logout link to the navigation menu.
+
 =cut
 
 sub logged_in_nav {
@@ -130,5 +155,15 @@
 
 }
 
+=head1 SEE ALSO
+
+L<Jifty::Plugin::Authentication::Password>, L<Jifty::Plugin::Authentication::Password::View>
+
+=head1 COPYRIGHT
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
 
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm	Sun Jul  1 23:56:36 2007
@@ -9,6 +9,40 @@
 
 our @EXPORT = qw(password_is hashed_password_is regenerate_auth_token has_alternative_auth);
 
+=head1 NAME
+
+Jifty::Plugin::Authentication::Password::Mixin::Model::User - password plugin user mixin model
+
+=head1 SYNOPSIS
+
+  package MyApp::Model::User;
+  use Jifty::DBI::Schema;
+  use MyApp::Record schema {
+      # custom column defrinitions
+  };
+
+  use Jifty::Plugin::User::Mixin::Model::User; # name, email, email_confirmed
+  use Jifty::Plugin::Authentication::Password::Mixin::Model::User;
+  # ^^ password, auth_token
+
+=head1 DESCRIPTION
+
+This mixin model is added to the application's account model for use with the password authentication plugin. This mixin should be used in combination with L<Jifty::Plugin::User::Mixin::Model::User>.
+
+=head1 SCHEMA
+
+This mixin adds the following columns to the model schema:
+
+=head2 auth_token
+
+This is a unique identifier used when confirming a user's email account and recovering a lost password.
+
+=head2 password
+
+This is the user's password. It will be stored in the database after being processed through L<Digest::MD5>, so the password cannot be directly recovered from the database.
+
+=cut
+
 use Jifty::Plugin::Authentication::Password::Record schema {
 
 
@@ -31,6 +65,14 @@
 
 };
 
+=head1 METHODS
+
+=head2 register_triggers
+
+Adds the triggers to the model this mixin is added to.
+
+=cut
+
 sub register_triggers {
     my $self = shift;
     $self->add_trigger(name => 'after_create', callback => \&after_create);
@@ -60,7 +102,9 @@
 =head2 hashed_password_is HASH TOKEN
 
 Check if the given I<HASH> is the result of hashing our (already
-salted and hashed) password with I<TOKEN>
+salted and hashed) password with I<TOKEN>.
+
+This can be used in cases where the pre-hashed password is sent during login as an additional security precaution (such as could be done via Javascript).
 
 =cut
 
@@ -93,6 +137,14 @@
     return 1;
 }
 
+=head2 after_create
+
+This trigger is added to the account model. It automatically sends a notification email to the user for password confirmation.
+
+See L<Jifty::Plugin::Authentication::Password::Notification::ConfirmEmail>.
+
+=cut
+
 
 sub after_create {
     my $self = shift;
@@ -143,7 +195,16 @@
     $self->__set(column => 'auth_token', value => $auth_token);
 }
 
+=head1 SEE ALSO
+
+L<Jifty::Plugin::Authentication::Password>, L<Jifty::Plugin::User::Mixin::Model>
 
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
 
 1;
 

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/View.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/View.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Authentication/Password/View.pm	Sun Jul  1 23:56:36 2007
@@ -4,12 +4,19 @@
 
 =head1 NAME
 
-Jifty::Plugin::Authentication::Password::Login::View
+Jifty::Plugin::Authentication::Password::View - views for password plugin
 
 =head1 DESCRIPTION
 
-This code is only useful on the new Jifty "Declarative tempaltes" branch. It shouldn't get in the way 
-if you're running a traditional (0.610 or before) Jifty.
+This code is only useful on the new Jifty "Declarative templates" branch. It shouldn't get in the way if you're running a traditional (0.610 or before) Jifty.
+
+=begin comment
+
+Is the above really true or need to said anymore? -- Sterling
+
+=end comment
+
+This provides the templates for the pages and forms used by the password authentication plugin.
 
 =cut
 
@@ -17,16 +24,22 @@
 use Jifty::View::Declare -base;
 
 { no warnings 'redefine';
-sub page (&) {
+sub page (&;$) {
     no strict 'refs'; 
     BEGIN {Jifty::Util->require(Jifty->app_class('View'))};
     Jifty->app_class('View')->can('page')->(@_);
 }
 }
 
+=head1 TEMPLATES
 
-template 'signup' => page {
-    title is _('Sign up');
+=head2 signup
+
+Displays a sign-up form.
+
+=cut
+
+template 'signup' => page { title => _('Sign up') } content {
     my ( $action, $next ) = get(qw(action next));
     Jifty->web->form->start( call => $next );
     render_param( $action => 'name' , focus => 1);
@@ -35,11 +48,26 @@
     Jifty->web->form->end();
 };
 
-template login => page {
-    { title is _('Login!') };
+=head2 login
+
+Displays the login form.
+
+=cut
+
+template login => page { title => _('Login!') } content {
     show('login_widget');
 };
 
+=head2 login_widget
+
+A handy template for embedding the login form. Just include it in your templates via:
+
+  show('login_widget');
+
+See L<Jifty::Plugin::Authentication::Password::Action::Login>.
+
+=cut
+
 template login_widget => sub {
 
     my ( $action, $next ) = get( 'action', 'next' );
@@ -69,9 +97,16 @@
     }
 };
 
-template 'let/reset_lost_password' => page {
+=head2 let/reset_lost_password
+
+After requesting a password reset and clicking on the link sent by email, this receives that click and provides the form for resetting the password.
+
+See L<Jifty::Plugin::Authentication::Action::ResetLostPassword>.
+
+=cut
+
+template 'let/reset_lost_password' => page { title => 'Reset lost password' } content {
     my ( $next ) = get(qw(next));
-    title is 'Reset lost password' ;
     my $action = Jifty->web->new_action( class => 'ResetLostPassword' );
 
     Jifty->web->form->start( call => $next );
@@ -80,19 +115,34 @@
     Jifty->web->form->end();
 };
 
+=head2 let/confirm_email
+
+Handles the work of confirming an email address for a new account.
+
+See L<Jifty::Plugin::Authenticaiton::Password::View>.
+
+=cut
+
 template 'let/confirm_email' => sub {
     new_action( class => 'ConfirmEmail' )->run;
     redirect("/");
 };
 
-template 'lost_password' => page {
+=head2 lost_password
+
+Starts the process of sending a link to reset a lost password by email.
+
+See L<Jifty::Plugin::Authentication::Password::SendPasswordReminder>.
+
+=cut
+
+template 'lost_password' => page { title => 'Send a link to reset your password' } content {
     my ( $next ) = get(qw(next));
     my $action = Jifty->web->new_action(
         moniker => 'password_reminder',
         class   => 'SendPasswordReminder',
     );
 
-    title is _('Send a link to reset your password');
     outs( _(  "You lost your password. A link to reset it will be sent to the following email address:"));
     my $focused = 0;
     Jifty->web->form->start( call => $next );
@@ -102,9 +152,22 @@
 
 };
 
-template 'passwordreminder' => page {
+=head2 passwordreminder
+
+Starts the process of sending a link to reset a lost password by email.
+
+See L<Jifty::Plugin::Authentication::Password::SendPasswordReminder>.
+
+=begin comment
+
+What's the difference between lost_password and passwordreminder? -- Sterling
+
+=end comment
+
+=cut
+
+template 'passwordreminder' => page { title => 'Send a password reminder' } content {
     my $next = get('next');
-     title is  _('Send a password reminder');
     my $action = Jifty->web->new_action(
         moniker => 'password_reminder',
         class   => 'SendPasswordReminder',
@@ -118,8 +181,15 @@
     Jifty->web->form->end();
 };
 
-template 'resend_confirmation' => page {
-    attr { title => "Resend Confirmation Email" };
+=head2 resend_confirmation
+
+Request a new email confirmation message be sent to your email account.
+
+See L<Jifty::Plugin::Authentication::Password::Action::ResendConfirmation>.
+
+=cut
+
+template 'resend_confirmation' => page { title => 'Resend Confirmation Email' } content {
     my $resend = Jifty->web->new_action(
         class   => 'ResendConfirmation',
         moniker => 'resendconf'
@@ -147,6 +217,16 @@
     }
 };
 
+=head1 SEE ALSO
+
+L<Jifty::Plugin::Authentication::Password>, L<Jifty::Plugin::Authentication::Password::Dispatcher>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
 
 
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS.pm	Sun Jul  1 23:56:36 2007
@@ -161,6 +161,12 @@
     }
 }
 
+=head2 minify_js \$js
+
+Runs the given JS through jsmin
+
+=cut
+
 sub minify_js {
     my $self = shift;
     my $input = shift;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/CompressedCSSandJS/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -63,7 +63,6 @@
 
 on '/__jifty/css/*' => run {
     my $arg = $1;
-    warn "My arg is $arg";
     if ( $arg !~ /^[0-9a-f]{32}\.css$/ ) {
 
         # This doesn't look like a real request for squished CSS,

Added: jifty/branches/virtual-models/lib/Jifty/Plugin/Debug.pm
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Debug.pm	Sun Jul  1 23:56:36 2007
@@ -0,0 +1,17 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::Debug;
+use base qw/Jifty::Plugin/;
+
+=head1 NAME
+
+Jifty::Plugin::Debug - a plugin to log each incoming request
+
+=head1 DESCRIPTION
+
+Enable this plugin in your F<etc/config.yml> (requires no configuration) and the plugin add an INFO level log message on each request received. It will contain the PID of the current process, the URL requested, and the username (if any) of the person making the request.
+
+=cut
+
+1;

Added: jifty/branches/virtual-models/lib/Jifty/Plugin/Debug/Dispatcher.pm
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Debug/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -0,0 +1,28 @@
+use warnings;
+use strict;
+
+package Jifty::Plugin::Debug::Dispatcher;
+use Jifty::Dispatcher -base;
+
+=head1 NAME
+
+Jifty::Plugin::Debug::Dispatcher - dispatcher for the debug plugin
+
+=head1 DESCRIPTION
+
+This adds a debugging rule to record debugging information about every request.
+
+=head1 RULES
+
+=head2 on qr'(.*)'
+
+Records the request. The INFO level log message recorded contains the PID of the current process, the URL requested, and the username (if any) attached to the current session.
+
+=cut
+
+on qr'(.*)' => run {
+    Jifty->log->info("[$$] $1 ".(Jifty->web->current_user->id ? Jifty->web->current_user->username : ''));
+};
+
+1;
+

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/ErrorTemplates/View.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/ErrorTemplates/View.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/ErrorTemplates/View.pm	Sun Jul  1 23:56:36 2007
@@ -55,7 +55,7 @@
 {
     no warnings qw'redefine';
 
-    sub wrapper ($) {
+    sub wrapper {
         my $code = shift;
         html {
             head {

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/Feedback/View.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/Feedback/View.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/Feedback/View.pm	Sun Jul  1 23:56:36 2007
@@ -4,6 +4,15 @@
 
 use Jifty::View::Declare -base;
 
+=head1 NAME
+
+Jifty::Plugin::Feedback::View
+
+=head1 DESCRIPTION
+
+Provides the feedback regions for L<Jifty::Plugin::Feedback>
+
+=cut
 
 template 'feedback/request_feedback' => sub {
     div {

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID.pm	Sun Jul  1 23:56:36 2007
@@ -4,4 +4,14 @@
 package Jifty::Plugin::OpenID;
 use base qw/Jifty::Plugin/;
 
+=head1 NAME
+
+Jifty::Plugin::OpenID
+
+=head1 DESCRIPTION
+
+Provides OpenID authentication for your app
+
+=cut
+
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Action/CreateOpenIDUser.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Action/CreateOpenIDUser.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Action/CreateOpenIDUser.pm	Sun Jul  1 23:56:36 2007
@@ -10,6 +10,12 @@
 package Jifty::Plugin::OpenID::Action::CreateOpenIDUser;
 use base qw/Jifty::Action::Record/;
 
+=head2 record_class 
+
+Returns the record class for this action
+
+=cut
+
 sub record_class {
     Jifty->app_class("Model", "User")
 }

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -4,6 +4,16 @@
 package Jifty::Plugin::OpenID::Dispatcher;
 use Jifty::Dispatcher -base;
 
+=head1 NAME
+
+Jifty::Plugin::OpenID::Dispatcher
+
+=head1 DESCRIPTION
+
+Dispatcher for L<Jifty::Plugin::OpenID>.  Handles a lot of the work.
+
+=cut
+
 before qr'^/(?:openid/link)' => run {
     tangent('/openid/login') unless (Jifty->web->current_user->id)
 };

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm	Sun Jul  1 23:56:36 2007
@@ -5,6 +5,16 @@
 use base 'Jifty::DBI::Record::Plugin';
 use URI;
 
+=head1 NAME
+
+Jifty::Plugin::OpenID::Mixin::Model::User
+
+=head1 DESCRIPTION
+
+L<Jifty::Plugin::OpenID> mixin for the User model.  Provides an 'openid' column.
+
+=cut
+
 use Jifty::Plugin::OpenID::Record schema {
 
 our @EXPORT = qw(has_alternative_auth link_to_openid);
@@ -18,14 +28,26 @@
 
 };
 
+=head2 has_alternative_auth
+
+=cut
+
 sub has_alternative_auth { 1 }
 
+=head2 register_triggers
+
+=cut
+
 sub register_triggers {
     my $self = shift;
     $self->add_trigger(name => 'validate_openid', callback => \&validate_openid, abortable => 1);
     $self->add_trigger(name => 'canonicalize_openid', callback => \&canonicalize_openid);
 }
 
+=head2 validate_openid
+
+=cut
+
 sub validate_openid {
     my $self   = shift;
     my $openid = shift;
@@ -45,6 +67,10 @@
     return 1;
 }
 
+=head2 canonicalize_openid
+
+=cut
+
 sub canonicalize_openid {
     my $self   = shift;
     my $openid = shift;
@@ -60,6 +86,12 @@
     return $uri->canonical;
 }
 
+=head2 link_to_openid
+
+Links User's account to the specified OpenID (bypassing ACLs)
+
+=cut
+
 sub link_to_openid {
     my $self   = shift;
     my $openid = shift;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/View.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/View.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/OpenID/View.pm	Sun Jul  1 23:56:36 2007
@@ -3,9 +3,19 @@
 use warnings;
 use Jifty::View::Declare -base;
 
+=head1 NAME
+
+Jifty::Plugin::OpenID::View
+
+=head1 DESCRIPTION
+
+The view class for L<Jifty::Plugin::OpenID>.  Provides login and create pages.
+
+=cut
+
 template 'openid/login' => page {
-    { title is _ "Login with your OpenID" }
-    my $action = get('action');
+    { title is _("Login with your OpenID") }
+    my ($action, $next) = get('action', 'next');
 
     div {
         unless ( Jifty->web->current_user->id ) {
@@ -19,13 +29,13 @@
                         }
                     }
                 );
-                form {
-                    render_action($action);
-                    form_submit(
-                        label  => _("Go for it!"),
-                        submit => $action
-                    );
-                }
+                Jifty->web->form->start( call => $next );
+                render_action($action);
+                form_submit(
+                    label  => _("Go for it!"),
+                    submit => $action
+                );
+                Jifty->web->form->end;
             };
         }
         else {

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage.pm	Sun Jul  1 23:56:36 2007
@@ -6,6 +6,20 @@
 
 __PACKAGE__->mk_accessors(qw(region_name));
 
+=head1 NAME
+
+Jifty::Plugin::SinglePage
+
+=head1 DESCRIPTION
+
+Makes your normal Jifty app into a single-page app through clever use of regions
+
+=head2 init
+
+Registers a before_new trigger to modify links and sets up the special region
+
+=cut
+
 sub init {
     my $self = shift;
     Jifty::Web::Form::Clickable->add_trigger( before_new => _sp_link($self));
@@ -33,12 +47,12 @@
                 args         => $args->{parameters}});
         }
         elsif (exists $args->{submit}) {
-	    $self->_push_onclick($args, { refresh_self => 1, submit => $args->{submit} });
-	    $args->{as_button} = 1;
-	}
+            $self->_push_onclick($args, { refresh_self => 1, submit => $args->{submit} });
+            $args->{as_button} = 1;
+        }
         if (my $form = delete $args->{_form}) {
-	    $args->{call} = $form->call;
-	}
+            $args->{call} = $form->call;
+        }
         my $onclick = $args->{onclick};
         if ( $args->{onclick} ) {
             $self->_push_onclick($args);    # make sure it's array

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/SinglePage/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -3,6 +3,16 @@
 use warnings;
 use Jifty::Dispatcher -base;
 
+=head1 NAME
+
+Jifty::Plugin::SinglePage::Dispatcher
+
+=head1 DESCRIPTION
+
+Dispatcher for L<Jifty::Plugin::SinglePage>
+
+=cut
+
 before '__jifty/webservices/*' => run {
     my (@actions) = grep { $_->class eq 'Jifty::Action::Redirect' } values %{ Jifty->web->request->{'actions'} };
     $_->active(0) for @actions;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews.pm	Sun Jul  1 23:56:36 2007
@@ -3,5 +3,14 @@
 package Jifty::Plugin::SiteNews;
 use base qw'Jifty::Plugin';
 
+=head1 NAME
+
+Jifty::Plugin::SiteNews
+
+=head1 DESCRIPTION
+
+Provides a way to include site news in your Jifty app
+
+=cut
 
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -4,6 +4,15 @@
 package Jifty::Plugin::SiteNews::Dispatcher;
 use base 'Jifty::Dispatcher';
 
+=head1 NAME
+
+Jifty::Plugin::SiteNews::Dispatcher
+
+=head1 DESCRIPTION
+
+Dispatcher for L<Jifty::Plugin::SiteNews>
+
+=cut
 
 
 

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/View/News.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/View/News.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/SiteNews/View/News.pm	Sun Jul  1 23:56:36 2007
@@ -5,10 +5,32 @@
 use Jifty::View::Declare -base;
 use Jifty::View::Declare::CRUD;
 
+=head1 NAME
+
+Jifty::Plugin::SiteNews::View::News
+
+=head1 DESCRIPTION
+
+The /news pages for L<Jifty::Plugin::SiteNews>
+
+=cut
+
 import_templates Jifty::View::Declare::CRUD under '/';
 
+=head2 object_type
+
+News
+
+=cut
+
 sub object_type { 'News' }
 
+=head2 fragment_base_path
+
+/news
+
+=cut
+
 sub fragment_base_path {'/news'}
 
 

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/SkeletonApp/View.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/SkeletonApp/View.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/SkeletonApp/View.pm	Sun Jul  1 23:56:36 2007
@@ -15,7 +15,9 @@
 =head1 DESCRIPTION
 
 This somewhat-finished (But not quite) template library implements
-Jifty's "pony" Application. It could certainly use some refactoring. (And some of the menu stuff should get factored out into a dispatcher or the other plugins that implement it.
+Jifty's "pony" Application. It could certainly use some
+refactoring. (And some of the menu stuff should get factored out into
+a dispatcher or the other plugins that implement it.
 
 
 =cut

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/User.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/User.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/User.pm	Sun Jul  1 23:56:36 2007
@@ -4,18 +4,22 @@
 package Jifty::Plugin::User;
 use base qw/Jifty::Plugin/;
 
-# Your plugin goes here.  If takes any configuration or arguments, you
-# probably want to override L<Jifty::Plugin/init>.
-
 =head1 NAME
 
-Jifty::Plugin::User
+Jifty::Plugin::User - plugin for building user models
 
 =head1 DESCRIPTION
 
 This plugin provides a "user" mixin for your application's user model class.
 
-See L<Jifty::Plugin::User/> for more details.
+=head1 SEE ALSO
+
+L<Jifty::Manual::AccessControl>, L<Jifty::Plugin::User::Mixin::Model::User>, L<Jifty::Plugin::Authentication::Password>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
 
 =cut
 

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/User/Mixin/Model/User.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/User/Mixin/Model/User.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/User/Mixin/Model/User.pm	Sun Jul  1 23:56:36 2007
@@ -7,9 +7,9 @@
 
 =head1 NAME
 
-Jifty::Plugin::User::Mixin::Model::User
+Jifty::Plugin::User::Mixin::Model::User - user model base mixin
 
-=head1 DESCRIPTION
+=head1 SYNOPSIS
 
  package MyApp::Model::User;
  use Jifty::DBI::Schema;
@@ -18,8 +18,27 @@
  };
  
  use Jifty::Plugin::User::Mixin::Model::User; # Imports two columns: name and email
- 
 
+=head1 DESCRIPTION
+
+This mixin may be added to a model to give your user accounts a name and an email address. This module may be used as the basic building block for building account models in your application. It can be combined with mixins from an authentication plugin to create an object suitable for a given authentication mechanism.
+
+=head1 SCHEMA
+
+This mixin model adds the following columns to the model.
+
+=head2 name
+
+This is the username/nickname for the user of the account.
+
+=head2 email
+
+This is the email address of the account. It is intended as a bare minimum confirmation of identity and for communication of password resets and other account information.
+
+=head2 email_confirmed
+
+This is a flag indicating whether the user has confirmed ownership of the given email address.
+ 
 =cut
 
 use base 'Jifty::DBI::Record::Plugin';
@@ -37,9 +56,7 @@
 
 };
 
-# Your model-specific methods go here.
-
-
+=head1 METHODS
 
 =head2 set_email ADDRESS
 
@@ -92,6 +109,16 @@
     return 1;
 }
 
+=head1 SEE ALSO
+
+L<Jifty::Plugin::Authentication::Password>, L<Jifty::Plugin::Authentication::Password::Mixin::Model::User>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
 
 1;
 

Modified: jifty/branches/virtual-models/lib/Jifty/Request.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Request.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Request.pm	Sun Jul  1 23:56:36 2007
@@ -513,7 +513,8 @@
     );
 
     # Set us up with the new continuation
-    Jifty->web->_redirect( Jifty->web->url(path => $path)
+    Jifty->web->_redirect( 
+                        $path
                       . ( $path =~ /\?/ ? "&" : "?" ) . "J:C="
                       . $c->id );
 }

Modified: jifty/branches/virtual-models/lib/Jifty/Request/Mapper.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Request/Mapper.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Request/Mapper.pm	Sun Jul  1 23:56:36 2007
@@ -87,7 +87,11 @@
             for (grep {/^(result(_of)?|argument(_to)?)$/} keys %mapping) {
                 my $action  = $mapping{$_};
                 my $moniker = ref $action ? $action->moniker : $action;
-                my $name = $mapping{name} || $key;
+                # If $key is for an argument of an action, we want to
+                # extract only the argument's name, and not just use
+                # the whole encoded J:A:F-... string.
+                my (undef, $a, undef) = Jifty::Request->parse_form_field_name($key);
+                my $name = $mapping{name} || $a || $key;
 
                 my $type = ($_ =~ /result/) ? "R" : "A";
 
@@ -120,7 +124,7 @@
 
 =item request
 
-The L<Jifty::Request> object to pull action arguments from.  Defauts
+The L<Jifty::Request> object to pull action arguments from.  Defaults
 to the current request.
 
 =item response

Modified: jifty/branches/virtual-models/lib/Jifty/Test.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Test.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Test.pm	Sun Jul  1 23:56:36 2007
@@ -158,9 +158,9 @@
     my $class = shift;
 
     my $test_config = File::Temp->new( UNLINK => 0 );
-    Jifty::YAML::DumpFile($test_config, $class->test_config(Jifty::Config->new));
+    Jifty::YAML::DumpFile("$test_config", $class->test_config(Jifty::Config->new));
     # Invoking bin/jifty and friends will now have the test config ready.
-    $ENV{'JIFTY_TEST_CONFIG'} ||= $test_config;
+    $ENV{'JIFTY_TEST_CONFIG'} ||= "$test_config";
     $class->builder->{test_config} = $test_config;
     {
         # Cache::Memcached stores things. And doesn't let them expire
@@ -187,7 +187,7 @@
     # Mason's disk caching sometimes causes false tests
     rmtree([ File::Spec->canonpath("$root/var/mason") ], 0, 1);
 
-$class->setup_test_database;
+    $class->setup_test_database;
 
     $class->setup_mailbox;
 }

Modified: jifty/branches/virtual-models/lib/Jifty/Upgrade.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Upgrade.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Upgrade.pm	Sun Jul  1 23:56:36 2007
@@ -152,4 +152,12 @@
     $package->just_renamed($renamed);
 }
 
+
+
+=head1 SEE ALSO
+
+L<Jifty::Manual::Upgrading>
+
+=cut
+
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/View.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View.pm	Sun Jul  1 23:56:36 2007
@@ -2,6 +2,16 @@
 use strict;
 use warnings;
 
+=head1 NAME
+
+Jifty::View - Base class for view modules
+
+=head1 DESCRIPTION
+
+This is the base class for L<Jifty::View::Declare> and L<Jifty::View::Mason::Handler>, which are the two view plugins shipped with Jifty. Other view plugins can be built by extending this class.
+
+=head1 METHODS
+
 =head2 auto_send_headers
 
 Doesn't send headers if this is a subrequest (according to the current
@@ -42,5 +52,17 @@
     }
 }
 
+=head1 SEE ALSO
+
+L<Jifty::View::Declare>, L<Jifty::View::Declare::BaseClass>, L<Jifty::View::Mason::Handler>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
+
+
 
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/View/Declare.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Declare.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Declare.pm	Sun Jul  1 23:56:36 2007
@@ -5,6 +5,10 @@
 use warnings;
 use constant BaseClass => 'Jifty::View::Declare::BaseClass';
 
+=head1 NAME
+
+Jifty::View::Declare - Build views using Template::Declare
+
 =head1 SYNOPSIS
 
     package MyApp::View;
@@ -15,6 +19,19 @@
         b { "The Index" };
     };
 
+=head1 DESCRIPTION
+
+L<Template::Declare> is a templating system using a declarative syntax built on top of Perl. This provides a templating language built in a similar style to the dispatcher language in L<Jifty::Dispatcher>, the model language in L<Jifty::DBI::Schema>, and the action language in L<Jifty::Param::Schema>.
+
+To use this view system, you must declare a class named C<MyApp::View> (where I<MyApp> is the name of your Jifyt application). Use this library class to bring in all the details needed to make it work:
+
+  package MyApp::View;
+  use Jifty::View::Declare -base;
+
+  # Your code...
+
+For more details on how to write the individual templates, see L<Template::Declare> and also L<Jifty::View::Declare::Helpers> for Jifty specific details.
+
 =cut
 
 sub import {
@@ -29,4 +46,15 @@
     goto &{BaseClass()->can('import')};
 }
 
+=head1 SEE ALSO 
+
+L<Jifty::View::Declare::Helpers>, L<Template::Declare>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distrib uted under the same terms as Perl itself.
+
+=cut
+
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/View/Declare/BaseClass.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Declare/BaseClass.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Declare/BaseClass.pm	Sun Jul  1 23:56:36 2007
@@ -12,25 +12,62 @@
 
 our @EXPORT = ( @Jifty::View::Declare::Helpers::EXPORT);
 
-
-1;
-__DATA__
-
 =head1 NAME
 
-Jifty::View::Declare::BaseClass
+Jifty::View::Declare::BaseClass - Base class for Template::Declare views
 
 =head1 DESCRIPTION
 
-This class provides a baseclass for your C<Template::Declare> derived view classes.
-
+This class provides a base class for your L<Template::Declare> derived view classes.
 
 =head1 METHODS
 
+=head2 use_mason_wrapper
+
+Call this function in your view class to use your mason wrapper for L<Template::Declare> templates.
+
+=cut
+
+sub use_mason_wrapper {
+    my $class = shift;
+    no strict 'refs';
+    no warnings 'redefine';
+    *{ $class . '::wrapper' } = sub {
+        my $code = shift;
+        my $args = shift;
+        # so in td handler, we made jifty::web->out appends to td
+        # buffer, we need it back for here before we call $code.
+        # someday we need to finish fixing the output system that is
+        # in Jifty::View.
+        my $td_out = \&Jifty::Web::out;
+        local *Jifty::Web::out = sub { shift->mason->out(@_) };
+
+        local *HTML::Mason::Request::content = sub {
+            local *Jifty::Web::out = $td_out;
+            $code->();
+            my $content = Template::Declare->buffer->data;
+            Template::Declare->buffer->clear;
+            $content;
+        };
+
+        Jifty->handler->fallback_view_handler->show('/_elements/wrapper', $args);
+    }
+}
+
+
 =head2 show templatename arguments
 
 Render a C<Template::Declare> template.
 
+=head1 SEE ALSO
+
+L<Template::Declare>, L<Jifty::View::Declare::Helpers>, L<Jifty::View::Declare>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
 
 =cut
 
+1;

Modified: jifty/branches/virtual-models/lib/Jifty/View/Declare/CRUD.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Declare/CRUD.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Declare/CRUD.pm	Sun Jul  1 23:56:36 2007
@@ -3,8 +3,26 @@
 
 package Jifty::View::Declare::CRUD;
 use Jifty::View::Declare -base;
-use base 'Exporter';
-our @EXPORT = qw(object_type fragment_for get_record current_collection);
+
+
+=head1 NAME
+
+Jifty::View::Declare::CRUD - Provides typical CRUD views to a model
+
+=head1 DESCRIPTION
+
+This class provides a set of views that may be used by a model to
+display Create/Read/Update/Delete views using the L<Template::Declare>
+templating langauge.
+
+=head1 METHODS
+
+=cut
+
+
+=head2 mount_view MODELCASS VIEWCLASS /path
+
+=cut
 
 sub mount_view {
     my ($class, $model, $vclass, $path) = @_;
@@ -21,11 +39,21 @@
     *{$vclass."::object_type"} = sub { $model };
 }
 
+
+=head2 object_type
+
+=cut
+
 sub object_type {
     my $self = shift;
     return $self->package_variable('object_type') || get('object_type');
 }
 
+
+=head2 fragment_for
+
+=cut
+
 sub fragment_for {
     my $self     = shift;
     my $fragment = shift;
@@ -38,12 +66,22 @@
         || $self->fragment_base_path . "/" . $fragment;
 }
 
+=head2 fragment_base_path
+
+=cut
+
 sub fragment_base_path {
     my $self = shift;
     return $self->package_variable('base_path') || '/crud';
 }
 
-sub get_record {
+=head2 _get_record $id
+
+Given an $id, returns a record object for the CRUD view's model class.
+
+=cut
+
+sub _get_record {
     my ( $self, $id ) = @_;
 
     my $record_class = Jifty->app_class( "Model", $self->object_type );
@@ -53,6 +91,51 @@
     return $record;
 }
 
+=head2 display_columns
+
+Returns a list of all the columns that this REST view should display
+
+=cut
+
+sub display_columns {
+    my $self = shift;
+    my $action = shift;
+     return   grep { !( m/_confirm/ || lc $action->arguments->{$_}{render_as} eq 'password' ) } $action->argument_names;
+}
+
+
+=head1 TEMPLATES
+
+
+=cut
+
+=head2 index.html
+
+
+=cut
+
+
+template 'index.html' => page {
+    my $self = shift;
+    title is $self->object_type;
+    form {
+            render_region(
+                name     => $self->object_type.'-list',
+                path     => $self->fragment_base_path.'/list');
+    }
+
+};
+
+ 
+
+
+
+=head2 search
+
+The search view displays a search screen connected to the search action of the module. See L<Jifty::Action::Record::Search>.
+
+=cut
+
 template 'search' => sub {
     my $self          = shift;
     my ($object_type) = ( $self->object_type );
@@ -78,39 +161,57 @@
         }
 };
 
-sub display_columns {
-    my $self = shift;
-    my $action = shift;
-     return   grep { !( m/_confirm/ || lc $action->arguments->{$_}{render_as} eq 'password' ) } $action->argument_names;
-}
 
+=head2 view
+
+This template displays the data held by a single model record.
+
+=cut
 
 template 'view' => sub {
     my $self = shift;
     my ( $object_type, $id ) = ( $self->object_type, get('id') );
+      my $record =   $self->_get_record($id);
     my $update = new_action(
         class   => 'Update' . $object_type,
         moniker => "update-" . Jifty->web->serial,
-        record  => $self->get_record($id)
+        record  => $record 
     );
 
     div {
         { class is 'crud read item inline' };
         my @fields =$self->display_columns($update);
         render_action( $update, \@fields, { render_mode => 'read' } );
+
+        show ('./view_item_controls', $record, $update); 
+
+        hr {};
+    };
+
+};
+
+private template view_item_controls  => sub {
+
+        my $self = shift;
+        my $record = shift;
+        my $action = shift;
         hyperlink(
             label   => "Edit",
             class   => "editlink",
             onclick => {
                 replace_with => $self->fragment_for('update'),
-                args         => { object_type => $object_type, id => $id }
+                args         => { object_type => $self->object_type, id => $record->id }
             },
         );
-
-        hr {};
     };
 
-};
+
+
+=head2 update
+
+The update template displays a form for editing the data held within a single model record. See L<Jifty::Action::Record::Update>.
+
+=cut
 
 template 'update' => sub {
     my $self = shift;
@@ -129,6 +230,27 @@
         { class is "crud update item inline " . $object_type }
 
         show('./edit_item', $update);
+        show('./edit_item_controls', $record, $update);
+
+        hr {};
+        }
+};
+
+
+
+=head2 edit_item_controls $record $action
+
+The controls we should be rendering in the 'edit' region for a given fragment
+
+=cut
+
+private template edit_item_controls => sub {
+    my $self = shift;
+    my $record = shift;
+    my $update = shift;
+
+    my $object_type = $self->object_type;
+    my $id = $record->id;
         div {
             { class is 'crud editlink' };
             hyperlink(
@@ -150,12 +272,32 @@
             );
         };
 
-        hr {};
-        }
 };
 
+=head2 list
+
+The list template provides an interactive list for showing a list of records in the record collection, adding new records, deleting records, and updating records.
+
+=cut
 
-sub current_collection {
+template 'list' => sub {
+    my $self = shift;
+
+    my ( $page ) = get(qw(page ));
+    my $fragment_for_new_item = get('fragment_for_new_item') || $self->fragment_for('new_item');
+    my $item_path = get('item_path') || $self->fragment_for("view");
+    my $collection =  $self->_current_collection();
+
+    show('./search_region');
+    show( './paging_top',    $collection, $page );
+    show( './list_items',    $collection, $item_path );
+    show( './paging_bottom', $collection, $page );
+    show( './new_item_region', $fragment_for_new_item );
+
+};
+
+
+sub _current_collection {
     my $self =shift; 
     my ( $page, $search_collection ) = get(qw(page  search_collection));
 
@@ -174,21 +316,12 @@
     return $collection;    
 }
 
-template 'list' => sub {
-    my $self = shift;
 
-    my ( $page ) = get(qw(page ));
-    my $fragment_for_new_item = get('fragment_for_new_item') || $self->fragment_for('new_item');
-    my $item_path = get('item_path') || $self->fragment_for("view");
-    my $collection =  $self->current_collection();
+=head2 search_region
 
-    show('./search_region');
-    show( './paging_top',    $collection, $page );
-    show( './list_items',    $collection, $item_path );
-    show( './paging_bottom', $collection, $page );
-    show( './new_item_region', $fragment_for_new_item );
+This I<private> template renders a region to show an expandable region for a search widget.
 
-};
+=cut
 
 private template 'search_region' => sub {
     my $self        = shift;
@@ -212,6 +345,14 @@
 
     outs( $search_region->render );
 };
+
+=head2 new_item_region
+
+This I<private> template renders a region to show a the C<new_item> template.
+
+=cut
+
+
 private template 'new_item_region' => sub {
     my $self        = shift;
     my $fragment_for_new_item = shift;
@@ -226,6 +367,15 @@
     }
 };
 
+
+=head2 list_items $collection $item_path
+
+Renders a div of class list with a region per item.
+
+
+
+=cut
+
 private template 'list_items' => sub {
     my $self        = shift;
     my $collection  = shift;
@@ -248,6 +398,14 @@
 
 };
 
+
+=head2 paging_top $collection $page_number
+
+Paging for your list, rendered at the top of the list
+
+=cut
+
+
 private template 'paging_top' => sub {
     my $self       = shift;
     my $collection = shift;
@@ -263,6 +421,12 @@
 
 };
 
+=head2 paging_bottom $collection $page_number
+
+Paging for your list, rendered at the bottom of the list
+
+=cut
+
 private template paging_bottom => sub {
     my $self       = shift;
     my $collection = shift;
@@ -294,12 +458,26 @@
 };
 
 
+
+=head2 edit_item $action
+
+Renders the action $Action, handing it the array ref returned by L</display_columns>.
+
+=cut
+
+
+
 private template 'edit_item' => sub {
     my $self = shift;
     my $action = shift;
     render_action($action, [$self->display_columns($action)]);
 };
 
+=head1 new_item
+
+The new_item template provides a form for creating new model records. See L<Jifty::Action::Record::Create>.
+
+=cut
 
 template 'new_item' => sub {
     my $self = shift;
@@ -333,5 +511,16 @@
         }
 };
 
+=head1 SEE ALSO
+
+L<Jifty::Action::Record::Create>, L<Jifty::Action::Record::Search>, L<Jifty::Action::Record::Update>, L<Jifty::Action::Record::Delete>, L<Template::Declare>, L<Jifty::View::Declare::Helpers>, L<Jifty::View::Declare>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2007 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl tiself.
+
+=cut
+
 1;
 

Modified: jifty/branches/virtual-models/lib/Jifty/View/Declare/Helpers.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Declare/Helpers.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Declare/Helpers.pm	Sun Jul  1 23:56:36 2007
@@ -5,7 +5,7 @@
 use base qw/Template::Declare Exporter/;
 use Template::Declare::Tags;
 
-our @EXPORT = ( qw(form hyperlink tangent redirect new_action form_submit form_return  form_next_page page wrapper request get set render_param current_user render_action render_region), @Template::Declare::Tags::EXPORT);
+our @EXPORT = ( qw(form hyperlink tangent redirect new_action form_submit form_return form_next_page page content wrapper request get set render_param current_user render_action render_region), @Template::Declare::Tags::EXPORT);
 
 =head1 NAME
 
@@ -264,27 +264,44 @@
 
  template 'foo' => page {{ title is 'Foo' } ... };
 
+  or
+
+ template 'foo' => page { title => 'Foo' } content { ... };
+
 Renders an HTML page wrapped in L</wrapper>, after calling
 "/_elements/nav" and setting a content type. Generally, you shouldn't
 be using "/_elements/nav" but a Dispatcher rule instead.
 
+If C<page/content> calling convention is used, the return value of the
+first sub will be passed into wrapper as the second argument as a
+hashref, as well as the last argument for the content sub.
+
 =cut
 
-sub page (&) {
-    my $code = shift;
+sub page (&;$) {
+    unshift @_, undef if $#_ == 0;
+    my ( $meta, $code ) = @_;
     sub {
         my $self = shift;
         Jifty->handler->apache->content_type('text/html; charset=utf-8');
-        if ( my $wrapper = Jifty->app_class('View')->can('wrapper') ) {
-            $wrapper->(sub { $code->($self)});
-        } else {
-
-        wrapper(sub { $code->($self) });
+        my $wrapper = Jifty->app_class('View')->can('wrapper') || \&wrapper;
+        my @metadata = $meta ? $meta->() : ();
+        my $metadata = $#metadata == 0 ? $metadata[0] : {@metadata};
+        local *is::title = sub { warn "Can't use 'title is' when mixing mason and TD" };
+        $wrapper->( sub { $code->( $self, $metadata ) }, $metadata );
     }
-    };
 }
 
+=head2 content
 
+Helper function for page { ... } content { ... }
+
+=cut
+
+sub content (&;$) {
+    # XXX: Check for only 1 arg
+    return $_[0];
+}
 
 =head2 wrapper $coderef
 
@@ -293,7 +310,7 @@
 
 =cut
 
-sub wrapper ($) {
+sub wrapper {
     my $app_class = get_current_attr('PageClass') || 'View::Page';
     delete $Template::Declare::Tags::ATTRIBUTES{ 'PageClass' };
 

Modified: jifty/branches/virtual-models/lib/Jifty/View/Declare/Page.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Declare/Page.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Declare/Page.pm	Sun Jul  1 23:56:36 2007
@@ -21,6 +21,12 @@
 __PACKAGE__->mk_accessors(qw(content_code done_header _title));
 use constant allow_single_page => 1;
 
+=head2 new
+
+Sets up a new page class
+
+=cut
+
 sub new {
     my $class = shift;
     my $self = $class->SUPER::new(@_);
@@ -127,6 +133,12 @@
     };
 }
 
+=head2 render_title
+
+Renders the in-page title
+
+=cut
+
 sub render_title {
     my $self = shift;
     my $oldt = get('title');
@@ -135,12 +147,23 @@
     set( title => $oldt );
 }
 
+=head2 render_footer
+
+Renders the page footer and prepends the header to the L<Template::Declare> buffer.
+
+=cut
+
 sub render_footer {
     my $self = shift;
     outs_raw('</html>');
     Template::Declare->buffer->data( $self->done_header . Template::Declare->buffer->data );
 }
 
+=head2 render_pre_content_hook
+
+Renders the AdminMode alert (if AdminMode is on)
+
+=cut
 
 sub render_pre_content_hook {
     if ( Jifty->config->framework('AdminMode') ) {
@@ -156,6 +179,12 @@
     }
 }
 
+=head2 render_jifty_page_detritus
+
+Renders the keybinding and PubSub javascript as well as the wait message
+
+=cut
+
 sub render_jifty_page_detritus {
 
     show('keybindings');

Modified: jifty/branches/virtual-models/lib/Jifty/View/Mason/Handler.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Mason/Handler.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Mason/Handler.pm	Sun Jul  1 23:56:36 2007
@@ -183,13 +183,13 @@
 }
 
 sub handle_comp {
-    my ($self, $comp) = (shift, shift);
+    my ($self, $comp, $args) = @_;
 
     # Set up the global
     my $r = Jifty->handler->apache;
     $self->interp->set_global('$r', $r);
 
-    my %args = $self->request_args($r);
+    my %args = $args ? %$args : $self->request_args($r);
 
     my @result;
     if (wantarray) {

Modified: jifty/branches/virtual-models/lib/Jifty/View/Static/Handler.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/View/Static/Handler.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/View/Static/Handler.pm	Sun Jul  1 23:56:36 2007
@@ -50,7 +50,20 @@
 =cut
 sub new {
     my $class = shift;
-    my $self = {};
+    
+    my @roots = (Jifty->config->framework('Web')->{StaticRoot});
+    for my $plugin ( Jifty->plugins ) {
+        my $root = $plugin->static_root;
+        if ( -d $root and -r $root ) {
+            push @roots, $root;
+            Jifty->log->debug( "Plugin @{[ref($plugin)]} static root added: (@{[$root ||'']})");
+        }
+    }
+    push @roots, (Jifty->config->framework('Web')->{DefaultStaticRoot});
+
+    my $self = {
+        roots => \@roots
+    };
     bless $self, $class;
 }
 
@@ -138,14 +151,11 @@
 sub file_path {
     my $self    = shift;
     my $file    = shift;
-    my @options = (Jifty->config->framework('Web')->{StaticRoot});
-    push @options, grep { -d $_ && -r $_ } map {$_->static_root} Jifty->plugins;
-    push @options, (Jifty->config->framework('Web')->{DefaultStaticRoot});
 
     # Chomp a leading "/static" - should this be configurable?
     $file =~ s/^\/*?static//; 
 
-    foreach my $path (@options) {
+    foreach my $path ( @{$self->{'roots'}} ) {
         my $abspath = Jifty::Util->absolute_path( File::Spec->catdir($path,$file ));
         # If the user is trying to request something outside our static root, 
         # decline the request

Modified: jifty/branches/virtual-models/lib/Jifty/Web.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web.pm	Sun Jul  1 23:56:36 2007
@@ -127,10 +127,6 @@
                 path => undef,
                 @_);
 
-    if ($args{'scheme'}) {
-        $self->log->error("Jifty->web->url no longer accepts a 'scheme' argument");
-    }
-
     my $uri;
 
     # Try to get a host out of the environment, useful in remote testing.
@@ -167,6 +163,10 @@
       $uri->port($port);
     }
 
+    if ( defined $args{'scheme'} ) {
+        $uri->scheme( $args{'scheme'} );
+    }
+
     if (defined $args{path}) {
       my $path = $args{path};
       # strip off leading '/' because ->canonical provides one
@@ -457,7 +457,9 @@
 
 =head3 new_action class => CLASS, moniker => MONIKER, order => ORDER, arguments => PARAMHASH
 
-Creates a new action (an instance of a subclass of L<Jifty::Action>). The named arguments passed to this method are passed on to the C<new> method of the action named in C<CLASS>.
+Creates a new action (an instance of a subclass of
+L<Jifty::Action>). The named arguments passed to this method are
+passed on to the C<new> method of the action named in C<CLASS>.
 
 =head3 Arguments
 
@@ -522,17 +524,6 @@
     $class = Jifty->api->qualify($class);
 
     my $loaded = Jifty::Util->require( $class );
-    $args{moniker} ||= ($loaded ? $class : 'Jifty::Action')->_generate_moniker;
-
-    my $action_in_request = $self->request->action( $args{moniker} );
-
-    # Fields explicitly passed to new_action take precedence over those passed
-    # from the request; we read from the request to implement "sticky fields".
-    #
-    if ( $action_in_request and $action_in_request->arguments ) {
-        $args{'request_arguments'} = $action_in_request->arguments;
-    }
-
     # The implementation class is provided by the client, so this
     # isn't a "shouldn't happen"
     return unless $loaded;

Modified: jifty/branches/virtual-models/lib/Jifty/Web/Form.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web/Form.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web/Form.pm	Sun Jul  1 23:56:36 2007
@@ -217,7 +217,18 @@
 
 sub submit {
     my $self = shift;
-    my $button = Jifty::Web::Form::Clickable->new(submit => undef, _form => $self, @_)->generate;
+    my %args = (submit => undef,
+                _form => $self,
+                @_);
+
+    my @submit = ref($args{'submit'}) eq 'ARRAY' ? @{$args{'submit'}} : $args{'submit'};
+    if ($self->actions->{'next_page'} && $submit[0] && ! grep {$_->moniker eq 'next_page' } @submit)  {
+        push @submit, $self->actions->{'next_page'};
+        $args{'submit'} = \@submit;
+    }
+
+
+    my $button = Jifty::Web::Form::Clickable->new(%args)->generate;
     Jifty->web->out(qq{<div class="submit_button">});
     $button->render_widget;
     Jifty->web->out(qq{</div>});

Modified: jifty/branches/virtual-models/lib/Jifty/Web/Form/Element.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web/Form/Element.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web/Form/Element.pm	Sun Jul  1 23:56:36 2007
@@ -326,7 +326,7 @@
         if (@fragments or (!$actions || %$actions)) {
 
             my $update = Jifty->web->escape("update( ". Jifty::JSON::objToJson( {actions => $actions, fragments => \@fragments, continuation => $self->continuation }, {singlequote => 1}) .", this );");
-            $string .= 'if(event.ctrlKey) return true; ';
+            $string .= 'if(event.ctrlKey||event.metaKey||event.altKey||event.shiftKey) return true; ';
             $string .= $self->javascript_preempt ? "return $update" : "$update; return true;";
         }
         if ($confirm) {

Modified: jifty/branches/virtual-models/lib/Jifty/Web/Form/Link.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web/Form/Link.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web/Form/Link.pm	Sun Jul  1 23:56:36 2007
@@ -101,12 +101,12 @@
 
     my $tooltip = $self->tooltip;
     $tooltip = Jifty->web->escape( $tooltip )
-        if ( $tooltip and $self->escape_label );
+        if ( defined $tooltip and $self->escape_label );
 
     Jifty->web->out(qq(<a));
     Jifty->web->out(qq( id="@{[$self->id]}"))         if $self->id;
     Jifty->web->out(qq( class="@{[$self->class]}"))   if $self->class;
-    Jifty->web->out(qq( title="@{[$self->tooltip]}")) if $tooltip;
+    Jifty->web->out(qq( title="@{[$tooltip]}"))       if defined $tooltip;
     Jifty->web->out(qq( target="@{[$self->target]}")) if $self->target;
     Jifty->web->out(qq( accesskey="@{[$self->key_binding]}")) if $self->key_binding;
     Jifty->web->out(qq( href="@{[Jifty->web->escape($self->url)]}"));

Modified: jifty/branches/virtual-models/lib/Jifty/Web/Session.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web/Session.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web/Session.pm	Sun Jul  1 23:56:36 2007
@@ -10,7 +10,14 @@
 
 Jifty::Web::Session - A Jifty session handler
 
-=cut
+=head1 SYNOPSIS
+
+In your F<etc/config.yml> (optional):
+
+  framework:
+    Web:
+      # The default ($PORT is replaced by the port the app is running on)
+      SessionCookieName: JIFTY_SID_$PORT
 
 =head2 new
 
@@ -22,12 +29,13 @@
     my $class = shift;
 
     my $session_class = Jifty->config->framework('Web')->{'SessionClass'};
+    my $cookie_name   = Jifty->config->framework('Web')->{'SessionCookieName'};
     if ($session_class and $class ne $session_class) {
         Jifty::Util->require( $session_class );
         return $session_class->new(@_);
     }
     else {
-        return bless {}, $class;
+        return bless { _cookie_name => $cookie_name }, $class;
     }
 }
 
@@ -302,7 +310,9 @@
 
 sub cookie_name {
     my $self = shift;
-    my $cookie_name = "JIFTY_SID_" . ( $ENV{'SERVER_PORT'} || 'NOPORT' );
+    my $cookie_name = $self->{'_cookie_name'};
+    my $port = ( $ENV{'SERVER_PORT'} || 'NOPORT' );
+    $cookie_name =~ s/\$PORT/$port/g;
     return ($cookie_name);
 }
 

Modified: jifty/branches/virtual-models/share/web/static/js/jifty.js
==============================================================================
--- jifty/branches/virtual-models/share/web/static/js/jifty.js	(original)
+++ jifty/branches/virtual-models/share/web/static/js/jifty.js	Sun Jul  1 23:56:36 2007
@@ -692,9 +692,10 @@
 	    }
 	    // We need to give the browser some "settle" time before
 	    // we eval scripts in the body
-	    YAHOO.util.Event.onAvailable(element.id, function() {
-		    (function() { this.evalScripts() }).bind(textContent)();
-		    Behaviour.apply(element) });
+        YAHOO.util.Event.onAvailable(element.id, function() {
+            (function() { this.evalScripts() }).bind(textContent)();
+        });
+        Behaviour.apply(element);
 	}
     }
     dom_fragment.setArgs(new_dom_args);

Modified: jifty/branches/virtual-models/share/web/static/js/yui/calendar.js
==============================================================================
--- jifty/branches/virtual-models/share/web/static/js/yui/calendar.js	(original)
+++ jifty/branches/virtual-models/share/web/static/js/yui/calendar.js	Sun Jul  1 23:56:36 2007
@@ -1,4 +1,8 @@
 /*
+    This file has been PATCHED by trs to allow selecting of out of month dates.
+    Please do not update it without also applying the patch (oom_select.patch).
+*/
+/*
 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
 Code licensed under the BSD License:
 http://developer.yahoo.net/yui/license.txt
@@ -903,6 +907,7 @@
 	MINDATE : {key:"mindate", value:null},
 	MAXDATE : {key:"maxdate", value:null},
 	MULTI_SELECT : {key:"multi_select",	value:false},
+	OOM_SELECT : {key:"oom_select",	value:false},
 	START_WEEKDAY : {key:"start_weekday", value:0},
 	SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
 	SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
@@ -1505,6 +1510,14 @@
 	*/
 	this.cfg.addProperty(defCfg.MULTI_SELECT.key,	{ value:defCfg.MULTI_SELECT.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
 
+    /**
+    * True if the Calendar should allow selection of out-of-month dates. False by default.
+    * @config OOM_SELECT
+    * @type Boolean
+    * @default false
+    */
+    this.cfg.addProperty(defCfg.OOM_SELECT.key,      { value:defCfg.OOM_SELECT.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
+
 	/**
 	* The weekday the week begins on. Default is 0 (Sunday).
 	* @config START_WEEKDAY
@@ -2176,7 +2189,7 @@
 		weekClass = weekPrefix + weekNum;
 
 		// Local OOM check for performance, since we already have pagedate
-		if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth()) {
+		if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth() && !this.cfg.getProperty(defCfg.OOM_SELECT.key)) {
 			break;
 		} else {
 
@@ -2203,7 +2216,7 @@
 				this.cellDates[this.cellDates.length] = workingArray; // Add this date to cellDates
 				
 				// Local OOM check for performance, since we already have pagedate
-				if (workingDate.getMonth() != useDate.getMonth()) {
+				if (workingDate.getMonth() != useDate.getMonth() && !this.cfg.getProperty(defCfg.OOM_SELECT.key)) {
 					cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
 				} else {
 					YAHOO.util.Dom.addClass(cell, workingDayPrefix + workingDate.getDay());

Added: jifty/branches/virtual-models/share/web/static/js/yui/oom_select.patch
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/share/web/static/js/yui/oom_select.patch	Sun Jul  1 23:56:36 2007
@@ -0,0 +1,54 @@
+=== share/web/static/js/yui/calendar.js
+==================================================================
+--- share/web/static/js/yui/calendar.js	(revision 24788)
++++ share/web/static/js/yui/calendar.js	(local)
+@@ -1,4 +1,8 @@
+ /*
++    This file has been PATCHED by trs to allow selecting of out of month dates.
++    Please do not update it without also applying the patch (oom_select.patch).
++*/
++/*
+ Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ Code licensed under the BSD License:
+ http://developer.yahoo.net/yui/license.txt
+@@ -903,6 +907,7 @@
+ 	MINDATE : {key:"mindate", value:null},
+ 	MAXDATE : {key:"maxdate", value:null},
+ 	MULTI_SELECT : {key:"multi_select",	value:false},
++	OOM_SELECT : {key:"oom_select",	value:false},
+ 	START_WEEKDAY : {key:"start_weekday", value:0},
+ 	SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
+ 	SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
+@@ -1505,6 +1510,14 @@
+ 	*/
+ 	this.cfg.addProperty(defCfg.MULTI_SELECT.key,	{ value:defCfg.MULTI_SELECT.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
+ 
++    /**
++    * True if the Calendar should allow selection of out-of-month dates. False by default.
++    * @config OOM_SELECT
++    * @type Boolean
++    * @default false
++    */
++    this.cfg.addProperty(defCfg.OOM_SELECT.key,      { value:defCfg.OOM_SELECT.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
++
+ 	/**
+ 	* The weekday the week begins on. Default is 0 (Sunday).
+ 	* @config START_WEEKDAY
+@@ -2176,7 +2189,7 @@
+ 		weekClass = weekPrefix + weekNum;
+ 
+ 		// Local OOM check for performance, since we already have pagedate
+-		if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth()) {
++		if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth() && !this.cfg.getProperty(defCfg.OOM_SELECT.key)) {
+ 			break;
+ 		} else {
+ 
+@@ -2203,7 +2216,7 @@
+ 				this.cellDates[this.cellDates.length] = workingArray; // Add this date to cellDates
+ 				
+ 				// Local OOM check for performance, since we already have pagedate
+-				if (workingDate.getMonth() != useDate.getMonth()) {
++				if (workingDate.getMonth() != useDate.getMonth() && !this.cfg.getProperty(defCfg.OOM_SELECT.key)) {
+ 					cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
+ 				} else {
+ 					YAHOO.util.Dom.addClass(cell, workingDayPrefix + workingDate.getDay());

Modified: jifty/branches/virtual-models/t/Mapper/lib/Mapper/Action/CrossBridge.pm
==============================================================================
--- jifty/branches/virtual-models/t/Mapper/lib/Mapper/Action/CrossBridge.pm	(original)
+++ jifty/branches/virtual-models/t/Mapper/lib/Mapper/Action/CrossBridge.pm	Sun Jul  1 23:56:36 2007
@@ -6,6 +6,7 @@
 param name      => default is 'something';
 param 'quest';
 param colour    => valid are ("Blue, I mean greeeeeen!", "Green");
+param 'castle';
 
 };
 

Modified: jifty/branches/virtual-models/t/Mapper/share/web/templates/index.html
==============================================================================
--- jifty/branches/virtual-models/t/Mapper/share/web/templates/index.html	(original)
+++ jifty/branches/virtual-models/t/Mapper/share/web/templates/index.html	Sun Jul  1 23:56:36 2007
@@ -11,6 +11,7 @@
 % my $grail_1  = Jifty->web->form->add_action( class => 'GetGrail', order => 1 );
 % my $bridge_1 = Jifty->web->new_action( class => 'CrossBridge',    order => 2 );
 <% $bridge_1->form_field( 'quest',  default_value => { result_of => $grail_1, name => 'castle' } ) %>
+<% $bridge_1->form_field( 'castle', default_value => { result_of => $grail_1 } ) %>
 <% $bridge_1->form_field( 'colour', default_value => 'Green' ) %>
 <% Jifty->web->form->submit( label => 'Do both') %>
 <% Jifty->web->form->end %>

Modified: jifty/branches/virtual-models/t/Mapper/t/02-api.t
==============================================================================
--- jifty/branches/virtual-models/t/Mapper/t/02-api.t	(original)
+++ jifty/branches/virtual-models/t/Mapper/t/02-api.t	Sun Jul  1 23:56:36 2007
@@ -12,7 +12,7 @@
 use lib 't/lib';
 use Jifty::SubTest;
 
-use Jifty::Test tests => 11;
+use Jifty::Test tests => 13;
 
 use_ok('Jifty::Test::WWW::Mechanize');
 
@@ -38,6 +38,11 @@
 $mech->content_like(qr/got the grail/i, "Got the grail");
 $mech->content_like(qr/crossed the bridge/i, "And crossed the bridge");
 
+# Tests for proper generation of default "name" parameter to
+# argument_of and result_to
+$mech->content_unlike(qr/R`[^']+`J:A:F/, "Doesn't have full argument name");
+$mech->content_like(qr/J:A:F-castle-(\S+): Aaaaaargh/, "Has the right value name");
+
 # And then, the same, but via default_values on the form field
 $mech->form_number(3);
 ok($mech->click_button(value => "Do both"));

Modified: jifty/branches/virtual-models/t/TestApp/lib/TestApp/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/t/TestApp/lib/TestApp/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/t/TestApp/lib/TestApp/Dispatcher.pm	Sun Jul  1 23:56:36 2007
@@ -82,4 +82,16 @@
     }
 };
 
+on HTTPS '/dispatch/protocol' => run {
+    set content => 'HTTPS';
+};
+
+on HTTP '/dispatch/protocol' => run {
+    set content => 'NOT HTTPS';
+};
+
+on '/dispatch/protocol' => run {
+    set footer => 'normal';
+};
+
 1;

Added: jifty/branches/virtual-models/t/TestApp/share/web/templates/dispatch/protocol
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/t/TestApp/share/web/templates/dispatch/protocol	Sun Jul  1 23:56:36 2007
@@ -0,0 +1,3 @@
+<&| /_elements/wrapper, title => "Test of protocol adjectives" &>
+<% Jifty::YAML::Dump(\%ARGS) %>
+</&>

Added: jifty/branches/virtual-models/t/TestApp/t/02-dispatch-http.t
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/t/TestApp/t/02-dispatch-http.t	Sun Jul  1 23:56:36 2007
@@ -0,0 +1,23 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+
+# Just in case
+BEGIN { delete $ENV{HTTPS}; }
+
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 5;
+use Jifty::Test::WWW::Mechanize;
+
+my $server  = Jifty::Test->make_server;
+
+isa_ok($server, 'Jifty::Server');
+
+my $URL     = $server->started_ok;
+my $mech    = Jifty::Test::WWW::Mechanize->new();
+
+$mech->get_ok("$URL/dispatch/protocol", "Got /dispatch/protocol");
+$mech->content_contains("NOT HTTPS");
+$mech->content_contains("normal");
+

Added: jifty/branches/virtual-models/t/TestApp/t/02-dispatch-https.t
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/t/TestApp/t/02-dispatch-https.t	Sun Jul  1 23:56:36 2007
@@ -0,0 +1,24 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+
+BEGIN { $ENV{HTTPS} = 1; }
+
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 6;
+use Jifty::Test::WWW::Mechanize;
+
+my $server  = Jifty::Test->make_server;
+
+isa_ok($server, 'Jifty::Server');
+
+my $URL     = $server->started_ok;
+my $mech    = Jifty::Test::WWW::Mechanize->new();
+
+$mech->get_ok("$URL/dispatch/protocol", "Got /dispatch/protocol");
+$mech->content_contains("HTTPS");
+$mech->content_lacks("NOT");
+$mech->content_contains("normal");
+
+


More information about the Jifty-commit mailing list