[Jifty-commit] r5059 - in jifty/branches/jquery: . lib/Jifty lib/Jifty/Manual lib/Jifty/Mason lib/Jifty/Plugin/Attributes lib/Jifty/Plugin/Attributes/Mixin lib/Jifty/Plugin/Attributes/Model lib/Jifty/Plugin/Authentication/Password/Mixin/Model lib/Jifty/Plugin/OAuth lib/Jifty/Plugin/OpenID lib/Jifty/Plugin/OpenID/Mixin/Model lib/Jifty/Plugin/SkeletonApp lib/Jifty/View/Declare lib/Jifty/View/Mason lib/Jifty/Web/Form lib/Jifty/Web/Form/Field share/po share/web/static/css share/web/static/js share/web/templates/__jifty share/web/templates/_elements t t/TestApp-Plugin-Attributes t/TestApp-Plugin-Attributes/bin t/TestApp-Plugin-Attributes/doc t/TestApp-Plugin-Attributes/etc t/TestApp-Plugin-Attributes/lib t/TestApp-Plugin-Attributes/lib/TestApp t/TestApp-Plugin-Attributes/lib/TestApp/Plugin t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Action t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Model t/TestApp-Plugin-Attributes/share t/TestApp-Plugin-Attributes/share/po t/TestApp-Plugin-Attributes/share/web t/TestApp-Plugin-Attributes/share/web/static t/TestApp-Plugin-Attributes/share/web/templates t/TestApp-Plugin-Attributes/t t/TestApp-Plugin-OAuth/lib/TestApp/Plugin/OAuth t/TestApp-Plugin-OAuth/t t/TestApp-Plugin-PasswordAuth/t

Jifty commits jifty-commit at lists.jifty.org
Wed Feb 6 12:23:58 EST 2008


Author: gugod
Date: Wed Feb  6 12:23:57 2008
New Revision: 5059

Added:
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes/
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes.pm
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Mixin/
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Mixin/Attributes.pm
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/Attribute.pm
   jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/AttributeCollection.pm
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/Makefile.PL
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/bin/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/bin/jifty   (contents, props changed)
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/doc/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/etc/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/etc/config.yml
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Action/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Model/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Model/Song.pm
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/share/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/share/po/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/share/web/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/share/web/static/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/share/web/templates/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/00-basic.t
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/01-content.t
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/02-crud-methods.t
   jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/03-permissions.t
Modified:
   jifty/branches/jquery/   (props changed)
   jifty/branches/jquery/META.yml
   jifty/branches/jquery/Makefile.PL
   jifty/branches/jquery/lib/Jifty/Dispatcher.pm
   jifty/branches/jquery/lib/Jifty/Manual/AccessControl.pod
   jifty/branches/jquery/lib/Jifty/Manual/Cookbook.pod
   jifty/branches/jquery/lib/Jifty/Mason/Halo.pm
   jifty/branches/jquery/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm
   jifty/branches/jquery/lib/Jifty/Plugin/Halo.pm
   jifty/branches/jquery/lib/Jifty/Plugin/I18N.pm
   jifty/branches/jquery/lib/Jifty/Plugin/OAuth/Dispatcher.pm
   jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Dispatcher.pm
   jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm
   jifty/branches/jquery/lib/Jifty/Plugin/SQLQueries.pm
   jifty/branches/jquery/lib/Jifty/Plugin/SkeletonApp/View.pm
   jifty/branches/jquery/lib/Jifty/Request.pm
   jifty/branches/jquery/lib/Jifty/View/Declare/Handler.pm
   jifty/branches/jquery/lib/Jifty/View/Declare/Helpers.pm
   jifty/branches/jquery/lib/Jifty/View/Mason/Handler.pm
   jifty/branches/jquery/lib/Jifty/Web/Form/Clickable.pm
   jifty/branches/jquery/lib/Jifty/Web/Form/Element.pm
   jifty/branches/jquery/lib/Jifty/Web/Form/Field.pm
   jifty/branches/jquery/lib/Jifty/Web/Form/Field/Combobox.pm
   jifty/branches/jquery/lib/Jifty/Web/Form/Field/Select.pm
   jifty/branches/jquery/lib/Jifty/Web/Form/Link.pm
   jifty/branches/jquery/share/po/zh_tw.po
   jifty/branches/jquery/share/web/static/css/halos.css
   jifty/branches/jquery/share/web/static/js/bps_util.js
   jifty/branches/jquery/share/web/static/js/halo.js
   jifty/branches/jquery/share/web/static/js/jifty.js
   jifty/branches/jquery/share/web/templates/__jifty/halo
   jifty/branches/jquery/share/web/templates/_elements/wrapper
   jifty/branches/jquery/t/01-dependencies.t
   jifty/branches/jquery/t/03-form-protocol.t
   jifty/branches/jquery/t/TestApp-Plugin-OAuth/lib/TestApp/Plugin/OAuth/Test.pm
   jifty/branches/jquery/t/TestApp-Plugin-OAuth/t/02-request-token.t
   jifty/branches/jquery/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t

Log:
- Merge /prj/mirror/jifty/trunk to /prj/mirror/jifty/branches/jquery

Modified: jifty/branches/jquery/META.yml
==============================================================================
--- jifty/branches/jquery/META.yml	(original)
+++ jifty/branches/jquery/META.yml	Wed Feb  6 12:23:57 2008
@@ -108,7 +108,7 @@
   IPC::PubSub: 0.23
   IPC::Run3: 0
   JSON::Syck: 0.15
-  Jifty::DBI: 0.47
+  Jifty::DBI: 0.49
   LWP::UserAgent: 0
   Locale::Maketext::Extract: 0.20
   Locale::Maketext::Lexicon: 0.60
@@ -137,6 +137,7 @@
   Test::WWW::Selenium: 0
   UNIVERSAL::require: 0
   URI: 1.31
+  URI::Escape: 0
   WWW::Mechanize: 1.3
   XML::Simple: 0
   XML::Writer: 0.601

Modified: jifty/branches/jquery/Makefile.PL
==============================================================================
--- jifty/branches/jquery/Makefile.PL	(original)
+++ jifty/branches/jquery/Makefile.PL	Wed Feb  6 12:23:57 2008
@@ -79,6 +79,7 @@
 requires('WWW::Mechanize' => 1.30 ),
 requires('UNIVERSAL::require');
 requires('URI' => 1.31);
+requires('URI::Escape');
 requires('XML::Writer' => '0.601');
 requires('XML::Simple');
 requires('XML::XPath');

Modified: jifty/branches/jquery/lib/Jifty/Dispatcher.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Dispatcher.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Dispatcher.pm	Wed Feb  6 12:23:57 2008
@@ -296,7 +296,7 @@
 sub default ($$@) { _ret @_ }    # set parameter if it's not yet set
 sub set ($$@)     { _ret @_ }    # set parameter
 sub del ($@)      { _ret @_ }    # remove parameter
-sub get ($) { request->argument( $_[0] ) }
+sub get ($) { request->template_argument( $_[0] ) || request->argument( $_[0] ) }
 
 sub _qualify ($@);
 sub GET ($)     { _qualify method => @_ }
@@ -473,7 +473,9 @@
     local $SIG{__DIE__} = 'DEFAULT';
 
     eval {
-        $Dispatcher->_do_dispatch( Jifty->web->request->path);
+        my $path = Jifty->web->request->path;
+        utf8::downgrade($path); # Mason handle non utf8 path.
+        $Dispatcher->_do_dispatch( $path );
     };
     if ( my $err = $@ ) {
         $self->log->warn(ref($err) . " " ."'$err'") if ( $err !~ /^ABORT/ );
@@ -798,7 +800,7 @@
 sub _do_set {
     my ( $self, $key, $value ) = @_;
     $self->log->debug("Setting argument $key to ".($value||''));
-    request->argument($key, $value);
+    request->template_argument($key, $value);
 }
 
 sub _do_del {
@@ -810,8 +812,8 @@
 sub _do_default {
     my ( $self, $key, $value ) = @_;
     $self->log->debug("Setting argument default $key to ".($value||''));
-    request->argument($key, $value)
-        unless defined request->argument($key);
+    request->template_argument($key, $value)
+        unless defined request->argument($key) or defined request->template_argument($key);
 }
 
 =head2 _do_dispatch [PATH]

Modified: jifty/branches/jquery/lib/Jifty/Manual/AccessControl.pod
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Manual/AccessControl.pod	(original)
+++ jifty/branches/jquery/lib/Jifty/Manual/AccessControl.pod	Wed Feb  6 12:23:57 2008
@@ -18,7 +18,7 @@
 if C<current_user_can('read')> returns false.
 
 On C<_set()> or C<I<set_somefieldname>>, we reject the operation
-if C<current_user_can('write')> returns false.
+if C<current_user_can('update')> returns false.
 
 
 On C<delete()>, we reject the operation if C<current_user_can('delete')>

Modified: jifty/branches/jquery/lib/Jifty/Manual/Cookbook.pod
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Manual/Cookbook.pod	(original)
+++ jifty/branches/jquery/lib/Jifty/Manual/Cookbook.pod	Wed Feb  6 12:23:57 2008
@@ -30,7 +30,7 @@
 
   __PACKAGE__->mk_accessors(qw(LDAP));
 
-and we can write our C<ldap_search> fonction. 
+and we can write our C<ldap_search> function. 
 Search need at least 3 characters and return an array of C<DisplayName (login)>
 
   sub ldap_search {

Modified: jifty/branches/jquery/lib/Jifty/Mason/Halo.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Mason/Halo.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Mason/Halo.pm	Wed Feb  6 12:23:57 2008
@@ -31,30 +31,16 @@
 
     return if ($context->comp->path || '') eq "/__jifty/halo";
 
-    my $ID          = Jifty->web->serial;
-    my $STACK       = Jifty->handler->stash->{'_halo_stack'} ||= [];
-    my $INDEX_STACK = Jifty->handler->stash->{'_halo_index_stack'} ||= [];
-    my $DEPTH       = ++Jifty->handler->stash->{'_halo_depth'};
-
-    my $frame = {
-        id           => $ID,
+    my $frame = Jifty::Plugin::Halo->push_frame(
         args         => [map { eval { defined $_ and fileno( $_ ) }  ? "*GLOB*" : $_} @{$context->args}],
-        start_time   => time,
         path         => $context->comp->path || '',
         subcomponent => $context->comp->is_subcomp() ? 1 : 0,
         name         => $context->comp->name || '(Unnamed component)',
         proscribed   => $self->_unrendered_component($context) ? 1 : 0,
-        depth        => $DEPTH,
-    };
-
-    my $previous = $STACK->[-1];
-    push @$STACK, $frame;
-    push @$INDEX_STACK, $#$STACK;
+    );
 
     return if $self->_unrendered_component($context);
 
-    $self->call_trigger('halo_pre_template', frame => $frame, previous => $previous);
-
     $context->request->out(Jifty::Plugin::Halo->halo_header($frame));
 }
 
@@ -71,18 +57,7 @@
 
     return if ($context->comp->path || '') eq "/__jifty/halo";
 
-    my $STACK       = Jifty->handler->stash->{'_halo_stack'};
-    my $INDEX_STACK = Jifty->handler->stash->{'_halo_index_stack'};
-    my $FRAME_ID    = pop @$INDEX_STACK;
-
-    my $frame = $STACK->[$FRAME_ID];
-    $frame->{'end_time'} = time;
-
-    my $previous = $FRAME_ID ? $STACK->[$FRAME_ID - 1] : {};
-
-    $self->call_trigger('halo_post_template', frame => $frame, previous => $previous);
-
-    --Jifty->handler->stash->{'_halo_depth'};
+    my $frame = Jifty::Plugin::Halo->pop_frame;
 
     return if $self->_unrendered_component($context);
 

Added: jifty/branches/jquery/lib/Jifty/Plugin/Attributes.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/lib/Jifty/Plugin/Attributes.pm	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,8 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::Attributes;
+use base 'Jifty::Plugin';
+
+1;
+

Added: jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Mixin/Attributes.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Mixin/Attributes.pm	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,144 @@
+#!/usr/bin/env perl
+package Jifty::Plugin::Attributes::Mixin::Attributes;
+use strict;
+use warnings;
+use Jifty::Plugin::Attributes::Model::Attribute;
+use Jifty::Plugin::Attributes::Model::AttributeCollection;
+
+use base 'Exporter';
+
+our @EXPORT = qw/attributes first_attribute add_attribute set_attribute
+                 delete_attribute/;
+
+=head2 attributes
+
+Returns an AttributeCollection limited to the invoking object.
+
+=cut
+
+sub attributes {
+    my $self = shift;
+    my $attrs = Jifty::Plugin::Attributes::Model::AttributeCollection->new;
+    $attrs->limit_to_object($self);
+}
+
+=head2 first_attribute name
+
+Returns the first attribute on this object with the given name, or C<undef> if
+none exist.
+
+=cut
+
+sub first_attribute {
+    my $self = shift;
+    my $name = shift;
+
+    $self->attributes->named($name)->first;
+}
+
+=head2 add_attribute PARAMHASH
+
+Adds the given attribute to this object. Returns the new attribute if
+successful, C<undef> otherwise. The following fields must be provided:
+
+=over 4
+
+=item name
+
+The name of the attribute
+
+=item description
+
+A description of the attribute
+
+=item content
+
+The attribute's value
+
+=back
+
+=cut
+
+sub add_attribute {
+    my $self = shift;
+    my %args = @_;
+
+    my $attr = Jifty::Plugin::Attributes::Model::Attribute->new;
+    $attr->create(
+        object      => $self,
+        name        => $args{name},
+        description => $args{description},
+        content     => $args{content},
+    );
+
+    return $attr->id ? $attr : undef;
+}
+
+=head2 set_attribute PARAMHASH
+
+Sets the given attribute on the object. Note that all existing attributes of
+that name will be removed. Returns the new attribute or C<undef> if one could
+not be created. The following fields must be provided:
+
+=over 4
+
+=item name
+
+The name of the attribute
+
+=item description
+
+A description of the attribute
+
+=item content
+
+The attribute's value
+
+=back
+
+=cut
+
+sub set_attribute {
+    my $self = shift;
+    my %args = @_;
+
+    my $attrs = $self->attributes->named($args{name});
+    if ($attrs->count == 0) {
+        return $self->add_attribute(%args);
+    }
+
+    my $saved = $attrs->first;
+
+    while (my $attr = $attrs->next) {
+        $attr->delete;
+    }
+
+    $saved->set_content($args{content});
+    $saved->set_description($args{description});
+
+    return $saved;
+}
+
+=head2 delete_attribute name
+
+Deletes all attributes of the given name. Returns a true value if all attributes
+were deleted, a false if any could not be.
+
+=cut
+
+sub delete_attribute {
+    my $self = shift;
+    my $name = shift;
+    my $ok = 1;
+
+    my $attrs = $self->attributes->named($name);
+    while (my $attr = $attrs->next) {
+        $attr->delete
+            or $ok = 0;
+    }
+
+    return $ok;
+}
+
+1;
+

Added: jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/Attribute.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/Attribute.pm	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,101 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+package Jifty::Plugin::Attributes::Model::Attribute;
+use base 'Jifty::Record';
+
+use Jifty::DBI::Schema;
+use Jifty::Record schema {
+    column name =>
+        type is 'text',
+        is mandatory;
+
+    column description =>
+        type is 'text';
+
+    column content =>
+        type is 'blob',
+        filters are 'Jifty::DBI::Filter::Storable';
+
+    column object_type =>
+        type is 'text',
+        is mandatory;
+
+    column object_id =>
+        type is 'int',
+        is mandatory;
+};
+
+=head2 before_create
+
+Let users pass in object instead of object_type and object_id.
+
+=cut
+
+sub before_create {
+    my $self = shift;
+    my $args = shift;
+
+    if (my $object = delete $args->{object}) {
+        $args->{object_type} = ref($object);
+        $args->{object_id}   = $object->id;
+    }
+
+    return 1;
+}
+
+=head2 current_user_can
+
+If you can read the original object, you can read its attributes. If you can
+update the original object, you can create, update, and delete its attributes.
+
+=cut
+
+sub current_user_can {
+    my $self  = shift;
+    my $right = shift;
+
+    # get a copy of the object
+    my ($type, $id);
+
+    if ($right eq 'create') {
+        my %args = @_;
+        ($type, $id) = $args{object}
+                     ? (ref($args{object}), $args{object}->id)
+                     : ($args{object_type}, $args{object_id});
+    }
+    else {
+        ($type, $id) = ($self->__value('object_type'), $self->__value('object_id'));
+    }
+
+    Carp::confess "No object given!" if !defined($type);
+
+    my $object = $type->new;
+    $object->load($id);
+
+    if ($right ne 'read') {
+        $right = 'update';
+    }
+
+    return $object->current_user_can($right, @_);
+}
+
+=head2 object
+
+Returns the object that owns this attribute.
+
+=cut
+
+sub object {
+    my $self = shift;
+    my ($type, $id) = ($self->object_type, $self->object_id);
+
+    my $object = $type->new;
+    $object->load($id);
+
+    return $object;
+}
+
+1;
+

Added: jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/AttributeCollection.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/lib/Jifty/Plugin/Attributes/Model/AttributeCollection.pm	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,52 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+package Jifty::Plugin::Attributes::Model::AttributeCollection;
+use base 'Jifty::Collection';
+
+=head2 record_class
+
+Is this even required any more?
+
+=cut
+
+sub record_class { 'Jifty::Plugin::Attributes::Model::Attribute' }
+
+=head2 named name
+
+Limits to attributes with the given name.
+
+=cut
+
+sub named {
+    my $self = shift;
+    my $name = shift;
+
+    $self->limit(column => 'name', value => $name);
+    return $self;
+}
+
+=head2 limit_to_object object
+
+Limits to attributes modifying the given object.
+
+=cut
+
+sub limit_to_object {
+    my $self = shift;
+    my $object = shift;
+
+    my $type = ref($object); # should this check be smarter?
+    return undef unless $type && $object->can('id');
+
+    my $id = $object->id;
+
+    $self->limit(column => 'object_type', value => $type);
+    $self->limit(column => 'object_id', value => $id);
+
+    return $self;
+}
+
+1;
+

Modified: jifty/branches/jquery/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/Authentication/Password/Mixin/Model/User.pm	Wed Feb  6 12:23:57 2008
@@ -60,7 +60,6 @@
   label is _('Password'),
   type is 'varchar(64)',
   max_length is 64,
-  lenght is 16,
   hints is _('Your password should be at least six characters'),
   render_as 'password',
   filters are 'Jifty::DBI::Filter::SaltHash';
@@ -135,7 +134,7 @@
     return 1 if $self->has_alternative_auth();
 
     return ( 0, _('Passwords need to be at least six characters long') )
-        if  length($new_value) && length($new_value) < 6;
+        if length($new_value) < 6;
 
     return 1;
 }

Modified: jifty/branches/jquery/lib/Jifty/Plugin/Halo.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/Halo.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/Halo.pm	Wed Feb  6 12:23:57 2008
@@ -34,7 +34,6 @@
         if Template::Declare->around_template;
 
     Template::Declare->around_template(sub { $self->around_template(@_) });
-
 }
 
 # parts of why this is.. weird is because we want to play nicely with Mason
@@ -42,96 +41,205 @@
 sub around_template {
     my ($self, $orig, $path, $args, $code) = @_;
 
-    my $ID          = Jifty->web->serial;
-    my $STACK       = Jifty->handler->stash->{'_halo_stack'} ||= [];
-    my $DEPTH       = ++Jifty->handler->stash->{'_halo_depth'};
-
     # for now, call the last piece of the template's path the name
     $path =~ m{.*/(.+)};
     my $name = $1 || $path;
 
-    my $deparsed = eval {
-        require Data::Dump::Streamer;
-        Data::Dump::Streamer::Dump($code)->Out;
+    my $frame = $self->push_frame(
+        args  => [ %{ Jifty->web->request->arguments } ],
+        path  => $path,
+        name  => $name,
+    );
+
+    $frame->{displays}->{P} = {
+        name     => "perl",
+        callback => sub {
+            my $deparsed = eval {
+                require Data::Dump::Streamer;
+                Data::Dump::Streamer::Dump($code)->Out;
+            };
+            Jifty->web->escape($deparsed);
+        },
     };
 
-    my $frame = {
-        id           => $ID,
-        args         => [ %{ Jifty->web->request->arguments } ], # ugh :)
-        start_time   => time,
-        path         => $path,
-        subcomponent => 0,
-        name         => $name,
-        proscribed   => 0,
-        depth        => $DEPTH,
-        perl         => $deparsed,
-    };
-
-    # if this is the first frame, discard anything from the previous queries
-    my $previous = $STACK->[-1] || {};
-
-    push @$STACK, $frame;
-    my $STACK_INDEX = $#$STACK;
-
-    $self->call_trigger('halo_pre_template', frame => $frame, previous => $previous);
-
     Template::Declare->buffer->append($self->halo_header($frame));
     $orig->();
-    Template::Declare->buffer->append($self->halo_footer($frame));
-
-    $frame->{'end_time'} = time;
 
-    $self->call_trigger('halo_post_template', frame => $frame, previous => $previous);
-
-    --Jifty->handler->stash->{'_halo_depth'};
+    $frame = $self->pop_frame;
+    Template::Declare->buffer->append($self->halo_footer($frame));
 }
 
 sub halo_header {
-    my $self  = shift;
-    my $frame = shift;
-    my $id    = $frame->{id};
-    my $perl  = $frame->{perl} || '';
-    my $name  = $frame->{name};
-
-    for ($perl, $name) {
-        $_ = Jifty->web->escape($_);
+    my $self     = shift;
+    my $frame    = shift;
+    my $id       = $frame->{id};
+    my $name     = Jifty->web->escape($frame->{name});
+    my $displays = $frame->{displays};
+
+    my @buttons;
+    for my $letter (sort keys %$displays) {
+        my $d = $displays->{$letter};
+        my $name = Jifty->web->escape($d->{name});
+
+        push @buttons, join "\n", grep { $_ }
+            qq{<a id="halo-button-$name-$id"},
+            qq{  onclick="halo_render('$id', '$name'); return false"},
+            $d->{default} && qq{  style="font-weight:bold"},
+            qq{  href="#">$letter</a>},
     }
 
-    my $perl_link = $perl ? qq{ | <a id="halo-button-perl-$id" onclick="halo_perl('$id'); return false" href="#">P</a> } : '';
-    my $perl_div = $perl ? qq{<div id="halo-perl-$id" class="halo_perl"><pre>$perl</pre></div>} : '';
+    my $rendermode = '[ ' . join(' | ', @buttons) . ' ]';
 
     return << "    HEADER";
         <div id="halo-$id" class="halo">
-            <div class="halo_header">
-                <span class="halo_rendermode">
-                    [
-                    <a style="font-weight: bold"
-                       id="halo-button-render-$id"
-                       onclick="halo_render('$id'); return false"
-                       href="#">R</a>
-                    |
-                    <a id="halo-button-source-$id"
-                       onclick="halo_source('$id'); return false"
-                       href="#">S</a>
-                    $perl_link
-                    ]
+            <div class="halo-header">
+                <span id="halo-rendermode-$id" class="halo-rendermode">
+                    $rendermode
                 </span>
-                <div class="halo_name">$name</div>
+                <div class="halo-name">$name</div>
             </div>
-            $perl_div
             <div id="halo-inner-$id">
+                <div id="halo-rendered-$id">
     HEADER
 }
 
 sub halo_footer {
-    my $self  = shift;
-    my $frame = shift;
+    my $self     = shift;
+    my $frame    = shift;
+    my $id       = $frame->{id};
+    my $displays = $frame->{displays};
+
+    my @divs;
+    for (sort keys %$displays) {
+        my $d = $displays->{$_};
+        my $name = Jifty->web->escape($d->{name});
+
+        if ($d->{callback}) {
+            my $output =
+                qq{<div id="halo-info-$name-$id" style="display: none">};
+
+            if (defined(my $info = $d->{callback}->($frame))) {
+                $output .= $info;
+            }
+            else {
+                # downgrade the link to plaintext so it's obvious there's no
+                # information available
+                $output .= qq{<script type="text/javascript">remove_link('$id', '$name');</script>};
+            }
+
+            $output .= "</div>";
+            push @divs, $output;
+        }
+    }
+
+    my $divs = join "\n", @divs;
 
     return << "    FOOTER";
+                </div>
+                <div id="halo-info-$id">
+                    $divs
+                </div>
             </div>
         </div>
     FOOTER
 }
 
+sub new_frame {
+    my $self = shift;
+
+    my $args = {
+        name => "arguments",
+        callback => sub {
+            my $frame = shift;
+            my @out;
+
+            my @args;
+            while (my ($key, $value) = splice(@{$frame->{args}},0,2)) {
+                push @args, [$key, $value];
+            }
+
+            for (sort { $a->[0] cmp $b->[0] } @args) {
+                my ($name, $value) = @$_;
+                my $ref = ref($value);
+                my $out = qq{<b>$name</b>: };
+
+                if ($ref) {
+                    my $expanded = Jifty->web->serial;
+                    my $yaml = Jifty->web->escape(Jifty::YAML::Dump($value));
+                    #$out .= qq{<a href="#" onclick="Element.toggle('$expanded'); return false">$ref</a><div id="$expanded" style="display: none; position: absolute; left: 200px; border: 1px solid black; background: #ccc; padding: 1em; padding-top: 0; width: 300px; height: 500px; overflow: auto"><pre>$yaml</pre></div>};
+                    $out .= qq{<a href="#" onclick="Element.toggle('$expanded'); return false">$ref</a><div id="$expanded" class="halo-argument" style="display: none"><pre>$yaml</pre></div>};
+                }
+                elsif (defined $value) {
+                    $out .= Jifty->web->escape($value);
+                }
+                else {
+                    $out .= "undef";
+                }
+
+                push @out, $out;
+            }
+
+            return undef if @out == 0;
+
+            return "<ul>"
+                 . join("\n",
+                        map { "<li>$_</li>" }
+                        @out)
+                 . "</ul>";
+        },
+    };
+
+    return {
+        id           => Jifty->web->serial,
+        start_time   => time,
+        subcomponent => 0,
+        proscribed   => 0,
+        displays     => {
+            R => { name => "render", default => 1 },
+            S => { name => "source" },
+            A => $args,
+        },
+        @_,
+    };
+}
+
+sub push_frame {
+    my $self = shift;
+
+    my $STACK       = Jifty->handler->stash->{'_halo_stack'} ||= [];
+    my $DEPTH       = ++Jifty->handler->stash->{'_halo_depth'};
+    my $INDEX_STACK = Jifty->handler->stash->{'_halo_index_stack'} ||= [];
+
+    # if this is the first frame, discard anything from the previous queries
+    my $previous = $STACK->[-1] || {};
+
+    my $frame = $self->new_frame(@_, previous => $previous, depth => $DEPTH);
+
+    push @$STACK, $frame;
+    push @$INDEX_STACK, $#$STACK;
+
+    $self->call_trigger('halo_pre_template', frame => $frame, previous => $previous);
+
+    return $frame;
+}
+
+sub pop_frame {
+    my $self = shift;
+
+    my $STACK       = Jifty->handler->stash->{'_halo_stack'} ||= [];
+    my $INDEX_STACK = Jifty->handler->stash->{'_halo_index_stack'} ||= [];
+    my $FRAME_ID    = pop @$INDEX_STACK;
+
+    my $frame = $STACK->[$FRAME_ID];
+    my $previous = $frame->{previous};
+
+    $frame->{'end_time'} = time;
+
+    $self->call_trigger('halo_post_template', frame => $frame, previous => $previous);
+
+    --Jifty->handler->stash->{'_halo_depth'};
+
+    return $frame;
+}
 
 1;

Modified: jifty/branches/jquery/lib/Jifty/Plugin/I18N.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/I18N.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/I18N.pm	Wed Feb  6 12:23:57 2008
@@ -48,6 +48,8 @@
 
 __PACKAGE__->mk_accessors(qw(js));
 
+Jifty->web->add_javascript('loc.js');
+
 sub init {
     my $self = shift;
     return if $self->_pre_init;

Modified: jifty/branches/jquery/lib/Jifty/Plugin/OAuth/Dispatcher.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/OAuth/Dispatcher.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/OAuth/Dispatcher.pm	Wed Feb  6 12:23:57 2008
@@ -8,6 +8,7 @@
 use Net::OAuth::AccessTokenRequest;
 use Net::OAuth::ProtectedResourceRequest;
 use Crypt::OpenSSL::RSA;
+use URI::Escape 'uri_unescape';
 
 on     POST '/oauth/request_token' => \&request_token;
 before GET  '/oauth/authorize'     => \&authorize;
@@ -344,11 +345,16 @@
 
 sub get_parameters {
     my %p;
+    my %params = Jifty->handler->apache->params();
 
-    # XXX: Check Authorization header
-    # XXX: Check WWW-Authenticate header
+    # Check Authorization header
+    my $authz = Jifty->handler->apache->header_in("Authorization");
+    if ($authz && $authz =~ s/^\s*OAuth\s*//i) {
+        while ($authz =~ m{\s*([%a-zA-Z0-9._~-]+)="([%a-zA-Z0-9._~-]*)"\s*}g) {
+            $params{uri_unescape($1)} = uri_unescape($2);
+        }
+    }
 
-    my %params = Jifty->handler->apache->params();
     for (@_) {
         $p{$_} = delete $params{"oauth_$_"}
             if !defined $p{$_};

Modified: jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Dispatcher.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Dispatcher.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Dispatcher.pm	Wed Feb  6 12:23:57 2008
@@ -19,6 +19,7 @@
 };
 
 before qr'^/openid/login' => run {
+    Jifty->api->allow('AuthenticateOpenID');
     set action => Jifty->web->new_action(
         class   => 'AuthenticateOpenID',
         moniker => 'authenticateopenid'
@@ -26,6 +27,7 @@
 };
 
 before qr'^/openid/verify' => run {
+    Jifty->api->allow('VerifyOpenID');
     Jifty->web->request->add_action(
         class   => 'VerifyOpenID',
         moniker => 'verifyopenid'
@@ -88,7 +90,11 @@
         }
     }
     else {
-        redirect '/openid/login';
+        if(Jifty->web->request->continuation) {
+            Jifty->web->request->continuation->call;
+        } else {
+            redirect '/openid/login';
+        }
     }
 };
 

Modified: jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/OpenID/Mixin/Model/User.pm	Wed Feb  6 12:23:57 2008
@@ -79,7 +79,7 @@
         if not defined $openid or not length $openid;
 
     $openid = 'http://' . $openid
-        if $openid !~ m{^http://};
+        if $openid !~ m{^https?://};
 
     my $uri = URI->new( $openid );
 

Modified: jifty/branches/jquery/lib/Jifty/Plugin/SQLQueries.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/SQLQueries.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/SQLQueries.pm	Wed Feb  6 12:23:57 2008
@@ -75,7 +75,14 @@
     require Carp;
 
     Jifty->handle->log_sql_statements(1);
-    Jifty->handle->log_sql_hook(SQLQueryPlugin => sub { Carp::longmess });
+    Jifty->handle->log_sql_hook(SQLQueryPlugin => sub {
+        my ($time, $statement, $bindings, $duration) = @_;
+        Jifty->log->debug(sprintf 'Query (%.3fs): "%s", with bindings: %s',
+                            $duration,
+                            $statement,
+                            join ', ', @$bindings);
+        return Carp::longmess;
+    });
 }
 
 =head2 before_request
@@ -86,8 +93,6 @@
 
 sub before_request {
     Jifty->handle or return;
-
-    Jifty->handle->clear_sql_statement_log();
 }
 
 =head2 after_request
@@ -103,18 +108,16 @@
     my $cgi = shift;
 
     my $total_time = 0;
-    my @log = (splice @halo_queries), Jifty->handle->sql_statement_log();
+    my @log = ((splice @halo_queries), Jifty->handle->sql_statement_log());
+    Jifty->handle->clear_sql_statement_log();
+
     for (@log) {
         my ($time, $statement, $bindings, $duration, $results) = @$_;
 
-        Jifty->log->debug(sprintf 'Query (%.3fs): "%s", with bindings: %s',
-                            $duration,
-                            $statement,
-                            join ', ', @$bindings);
         $total_time += $duration;
 
         # keep track of the ten slowest queries so far
-        if ($duration > $slow_queries[0][3]) {
+        if (@slow_queries < 10 || $duration > $slow_queries[0][3]) {
             push @slow_queries, $_;
             @slow_queries = sort { $a->[3] <=> $b->[3] } @slow_queries;
             shift @slow_queries if @slow_queries > 9;
@@ -146,6 +149,50 @@
     push @halo_queries, Jifty->handle->sql_statement_log;
 
     Jifty->handle->clear_sql_statement_log;
+
+    $args{frame}{displays}{Q} = {
+        name => "queries",
+        callback => sub {
+            my $frame = shift;
+            my @queries;
+
+            for (@{ $frame->{sql_statements} || [] }) {
+                my $bindings;
+
+                if (@{$_->[2]}) {
+                    my @bindings = map {
+                        defined $_
+                            ? $_ =~ /[^[:space:][:graph:]]/
+                                ? "*BLOB*"
+                                : Jifty->web->escape($_)
+                            : "undef"
+                    } @{$_->[2]};
+
+                    $bindings = join '',
+                        "<b>",
+                        _('Bindings'),
+                        ":</b> <tt>",
+                        join(', ', @bindings),
+                        "</tt><br />",
+                }
+
+                push @queries, join "\n",
+                    qq{<span class="fixed">},
+                    Jifty->web->escape($_->[1]),
+                    qq{</span><br />},
+                    defined($bindings) ? $bindings : '',
+                    "<i>". _('%1 seconds', $_->[3]) ."</i>",
+            }
+
+            return undef if @queries == 0;
+
+            return "<ol>"
+                 . join("\n",
+                        map { "<li>$_</li>" }
+                        @queries)
+                 . "</ol>";
+        },
+    };
 }
 
 =head2 halo_post_template

Modified: jifty/branches/jquery/lib/Jifty/Plugin/SkeletonApp/View.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Plugin/SkeletonApp/View.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Plugin/SkeletonApp/View.pm	Wed Feb  6 12:23:57 2008
@@ -69,7 +69,7 @@
 
 private template 'keybindings' => sub {
     div { id is "keybindings";
-      outs_raw('<script type="text/javascript"><!-- Jifty.KeyBindings.reset() --></script>') };
+      outs_raw('<script type="text/javascript">Jifty.KeyBindings.reset()</script>') };
 };
 
 #template 'index.html' => page { { title is _('Welcome to your new Jifty application') } img { src is "/static/images/pony.jpg", alt is _( 'You said you wanted a pony. (Source %1)', 'http://hdl.loc.gov/loc.pnp/cph.3c13461'); }; };

Modified: jifty/branches/jquery/lib/Jifty/Request.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Request.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Request.pm	Wed Feb  6 12:23:57 2008
@@ -4,7 +4,7 @@
 package Jifty::Request;
 
 use base qw/Jifty::Object Class::Accessor::Fast/;
-__PACKAGE__->mk_accessors(qw(_top_request arguments just_validating path continuation_id continuation_type continuation_path));
+__PACKAGE__->mk_accessors(qw(_top_request arguments template_arguments just_validating path continuation_id continuation_type continuation_path));
 
 use Jifty::JSON;
 use Jifty::YAML;
@@ -80,6 +80,7 @@
     $self->{'state_variables'} = {};
     $self->{'fragments'} = {};
     $self->arguments({});
+    $self->template_arguments({});
 
     my %args = @_;
     for (keys %args) {
@@ -359,6 +360,27 @@
     $val;
 }
 
+=head2 template_argument KEY [=> VALUE]
+
+Sets an argument for the current template.  Template arguments, unlike
+values set via L</argument>, B<cannot> add actions, change action
+argument, or change state variables.  They are also not stored in
+continuations.
+
+=cut
+
+sub template_argument {
+    my $self = shift;
+
+    my $key = shift;
+    if (@_) {
+        my $value = shift;
+        $self->template_arguments->{$key} = $value;
+    }
+    defined(my $val = $self->template_arguments->{$key}) or return undef;
+    $val;
+}
+
 =head2 delete KEY
 
 Removes the argument supplied -- this is the opposite of L</argument>,
@@ -370,6 +392,10 @@
     my $self = shift;
 
     my $key = shift;
+    if (exists $self->template_arguments->{$key}) {
+        delete $self->template_arguments->{$key};
+        return;
+    }
     delete $self->arguments->{$key};
     if ($key =~ /^J:A-(?:(\d+)-)?(.+)/s) {
         $self->remove_action($2);
@@ -532,6 +558,10 @@
     # continuation" into the continuation!
     $self->continuation_path(undef);
 
+    # Clear out the (locally-set) template arguments, which would
+    # bloat the continuation, and can be entirely re-generated.
+    $self->template_arguments({});
+
     my $c = Jifty::Continuation->new(
         request  => $self,
         response => Jifty->web->response,

Modified: jifty/branches/jquery/lib/Jifty/View/Declare/Handler.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/View/Declare/Handler.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/View/Declare/Handler.pm	Wed Feb  6 12:23:57 2008
@@ -75,7 +75,7 @@
         goto &Template::Declare::Tags::outs_raw;
     };
     
-    my $content = Template::Declare::Tags::show_page( $template, Jifty->web->request->arguments );
+    my $content = Template::Declare::Tags::show_page( $template, { %{Jifty->web->request->template_arguments}, %{Jifty->web->request->arguments} } );
     return unless defined $content;
 
     my $r = Jifty->handler->apache;

Modified: jifty/branches/jquery/lib/Jifty/View/Declare/Helpers.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/View/Declare/Helpers.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/View/Declare/Helpers.pm	Wed Feb  6 12:23:57 2008
@@ -234,9 +234,9 @@
 
 sub get {
     if (wantarray) {
-        map { request->argument($_) } @_;
+        map { request->template_argument($_) || request->argument($_) } @_;
     } else {
-        request->argument( $_[0] );
+        request->template_argument($_[0]) || request->argument( $_[0] );
     }
 }
 
@@ -251,7 +251,7 @@
 
 sub set {
     while ( my ( $arg, $val ) = splice(@_, 0, 2) ) {
-        request->argument( $arg => $val );
+        request->template_argument( $arg => $val );
     }
 
 }

Modified: jifty/branches/jquery/lib/Jifty/View/Mason/Handler.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/View/Mason/Handler.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/View/Mason/Handler.pm	Wed Feb  6 12:23:57 2008
@@ -231,7 +231,7 @@
 =cut
 
 sub request_args {
-    return %{Jifty->web->request->arguments};
+    return %{Jifty->web->request->template_arguments}, %{Jifty->web->request->arguments};
 }
 
 ###########################################################

Modified: jifty/branches/jquery/lib/Jifty/Web/Form/Clickable.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Web/Form/Clickable.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Web/Form/Clickable.pm	Wed Feb  6 12:23:57 2008
@@ -549,6 +549,7 @@
         {   %$args,
             type         => 'InlineButton',
             continuation => $self->_continuation,
+            title        => $self->tooltip,
             @_
         }
     );

Modified: jifty/branches/jquery/lib/Jifty/Web/Form/Element.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Web/Form/Element.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Web/Form/Element.pm	Wed Feb  6 12:23:57 2008
@@ -571,11 +571,9 @@
     my $self = shift;
     return unless $self->key_binding;
     Jifty->web->out(
-        '<script type="text/javascript"><!--' .
-        "\n" .
+        '<script type="text/javascript">' .
         Jifty->web->escape($self->key_binding_javascript).
-        "\n" .
-        "--></script>");
+        "</script>");
     return '';
 }
 

Modified: jifty/branches/jquery/lib/Jifty/Web/Form/Field.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Web/Form/Field.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Web/Form/Field.pm	Wed Feb  6 12:23:57 2008
@@ -392,9 +392,7 @@
     );
     
     if($javascript =~ /\S/) {
-        Jifty->web->out(qq{<script type="text/javascript"><!--
-    $javascript
---></script>
+        Jifty->web->out(qq{<script type="text/javascript">$javascript</script>
 });
     }
 }
@@ -608,9 +606,7 @@
     my $self = shift;
     return unless $self->autocompleter;
     $self->render_autocomplete_div;
-    Jifty->web->out(qq{<script type="text/javascript"><!--
-    @{[$self->autocomplete_javascript]}
---></script>});
+    Jifty->web->out(qq{<script type="text/javascript">@{[$self->autocomplete_javascript]}</script>});
     return '';
 }
 

Modified: jifty/branches/jquery/lib/Jifty/Web/Form/Field/Combobox.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Web/Form/Field/Combobox.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Web/Form/Field/Combobox.pm	Wed Feb  6 12:23:57 2008
@@ -59,9 +59,9 @@
 
 $field .= <<"EOF";
 </select>
-<script language="javascript"><!--
+<script language="javascript">
 ComboBox_InitWith('@{[ $self->element_id ]}');
-//--></script>
+</script>
 </nobr>
 EOF
 

Modified: jifty/branches/jquery/lib/Jifty/Web/Form/Field/Select.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Web/Form/Field/Select.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Web/Form/Field/Select.pm	Wed Feb  6 12:23:57 2008
@@ -30,7 +30,7 @@
         my $display = $opt->{'display'};
         my $value   = $opt->{'value'};
         $value = "" unless defined $value;
-        $field .= qq!<option value="$value"!;
+        $field .= qq!<option value="@{[ Jifty->web->escape($value) ]}"!;
         $field .= qq! selected="selected"!  if defined $self->current_value and $self->current_value eq $value;
         $field .= qq!>!;
         $field .= Jifty->web->escape(_($display)) if defined $display;

Modified: jifty/branches/jquery/lib/Jifty/Web/Form/Link.pm
==============================================================================
--- jifty/branches/jquery/lib/Jifty/Web/Form/Link.pm	(original)
+++ jifty/branches/jquery/lib/Jifty/Web/Form/Link.pm	Wed Feb  6 12:23:57 2008
@@ -117,11 +117,9 @@
     $output .= (qq(>$label</a>));
 
     $output .= (
-        '<script type="text/javascript"><!--' .
-        "\n" .
+        '<script type="text/javascript">' .
         Jifty->web->escape($self->key_binding_javascript).
-        "\n" .
-        "--></script>") if $self->key_binding;
+        "</script>") if $self->key_binding;
 
     return $output;
 }

Modified: jifty/branches/jquery/share/po/zh_tw.po
==============================================================================
--- jifty/branches/jquery/share/po/zh_tw.po	(original)
+++ jifty/branches/jquery/share/po/zh_tw.po	Wed Feb  6 12:23:57 2008
@@ -375,7 +375,7 @@
 
 #: lib/Jifty/Plugin/OpenID/Action/AuthenticateOpenID.pm:59
 msgid "Invalid OpenID URL.  Please check to make sure it is correct.  (@{[$csr->err]})"
-msgstr ""
+msgstr "不正確的 OpenID 網址. (@{[$csr->err]})"
 
 #: lib/Jifty/Plugin/Authentication/Password/Action/Login.pm:63 lib/Jifty/Plugin/Authentication/Password/Action/SendAccountConfirmation.pm:75 lib/Jifty/Plugin/Authentication/Password/Action/SendPasswordReminder.pm:79
 msgid "It doesn't look like there's an account by that name."
@@ -383,11 +383,11 @@
 
 #: lib/Jifty/Plugin/User/Mixin/Model/User.pm:106
 msgid "It looks like somebody else is using that address. Is there a chance you have another account?"
-msgstr ""
+msgstr "已經有其他人使用這個電郵地址. 您是否已經有其他帳號了?"
 
 #: lib/Jifty/Plugin/OpenID/Dispatcher.pm:43
 msgid "It looks like someone is already using that OpenID."
-msgstr ""
+msgstr "已經有其他人使用此 OpenID."
 
 #: lib/Jifty/Plugin/Authentication/Password/Action/Signup.pm:75
 msgid "It looks like you already have an account. Perhaps you want to <a href=\"/login\">log in</a> instead?"
@@ -511,7 +511,7 @@
 
 #: lib/Jifty/Plugin/OpenID/Action/AuthenticateOpenID.pm:27
 msgid "OpenID URL"
-msgstr ""
+msgstr "OpenID 網址"
 
 #: lib/Jifty/Plugin/OpenID/Action/VerifyOpenID.pm:54
 msgid "OpenID verification failed.  It looks like you cancelled the OpenID verification request."

Modified: jifty/branches/jquery/share/web/static/css/halos.css
==============================================================================
--- jifty/branches/jquery/share/web/static/css/halos.css	(original)
+++ jifty/branches/jquery/share/web/static/css/halos.css	Wed Feb  6 12:23:57 2008
@@ -3,24 +3,34 @@
     border-style: solid;
     border-width: 0;
     margin: 0;
+    padding: 0;
 }
 
-.halo_header {
+.halo-header {
     display: none;
-    border-bottom: 1px dashed #ffd700;
+    border-bottom: 1px solid #ffd700;
     background: #fff;
+    margin: 3px;
 }
 
-.halo_rendermode {
+.halo-rendermode {
     float: right;
 }
 
-.halo_source, .halo_perl {
+.halo-source {
     font-family: monospace;
 }
 
-.halo_perl {
-    display: none;
+.halo-argument {
+    position: absolute;
+    left: 200px;
+    border: 1px solid black;
+    background: #ccc;
+    padding: 1em;
+    padding-top: 0;
+    width: 300px;
+    height: 500px;
+    overflow: auto;
 }
 
 .halo_actions {

Modified: jifty/branches/jquery/share/web/static/js/bps_util.js
==============================================================================
--- jifty/branches/jquery/share/web/static/js/bps_util.js	(original)
+++ jifty/branches/jquery/share/web/static/js/bps_util.js	Wed Feb  6 12:23:57 2008
@@ -43,6 +43,7 @@
         });
     }
     link.setAttribute("onclick", onclick);
+    link.setAttribute("title", e.getAttribute("title"));
 
     link.className = e.className;
     link["virtualform"] = form;

Modified: jifty/branches/jquery/share/web/static/js/halo.js
==============================================================================
--- jifty/branches/jquery/share/web/static/js/halo.js	(original)
+++ jifty/branches/jquery/share/web/static/js/halo.js	Wed Feb  6 12:23:57 2008
@@ -66,63 +66,91 @@
     var halo_header_display = 'none';
     var halo_border_width   = '0';
     var halo_margin         = '0';
+    var halo_padding        = '0';
 
     halos_drawn = !halos_drawn;
 
     if (halos_drawn) {
         halo_header_display = 'block';
-        halo_border_width   = '1px';
-        halo_margin         = '2px';
+        halo_border_width   = '2px';
+        halo_margin         = '3px';
+        halo_padding        = '3px';
     }
 
-    jQuery(".halo_header").css({
-        display: halo_header_display
-    });
-
-    jQuery(".halo").css({
-        'border-width': halo_border_width,
-        'margin': halo_margin
-    });
+    $("render_info-draw_halos").innerHTML = halos_drawn ? "Hide halos" : "Draw halos";
+
+    YAHOO.util.Dom.getElementsByClassName("halo-header", null, null,
+        function (e) {
+            e.style.display = halo_header_display;
+        }
+    );
+
+    YAHOO.util.Dom.getElementsByClassName("halo", null, null,
+        function (e) {
+            e.style.borderWidth = halo_border_width;
+            e.style.margin = halo_margin;
+            e.style.padding = halo_padding;
+        }
+    );
 }
 
 function render_info_tree() {
     jQuery("#render_info_tree").toggle();
 }
 
-function halo_render(id) {
+function halo_render(id, name) {
     halo_reset(id);
-    jQuery('#halo-button-render-'+id).css({ 'font-weight': 'bold' });
+    $('halo-button-'+name+'-'+id).style.fontWeight = 'bold';
 
-    var e = Jifty.$('halo-inner-'+id);
-    if (e.halo_rendered) {
-        e.innerHTML = e.halo_rendered;
-        e.halo_rendered = null;
+    var e = $('halo-rendered-'+id);
+
+    if (name == 'source') {
+        e.halo_rendered = e.innerHTML;
+        e.innerHTML = '<div class="halo-source">' + e.innerHTML.escapeHTML() + '</div>';
+    }
+    else if (name == 'render') {
+        /* ignore */
+    }
+    else {
+        e.style.display = 'none';
+        $('halo-info-'+id).style.display = 'block';
+        $('halo-info-'+name+'-'+id).style.display = 'block';
     }
 }
 
-function halo_source(id) {
-    halo_reset(id);
-    Jifty.$('halo-button-source-'+id).style.fontWeight = 'bold';
+function halo_reset(id) {
+    /* restore all buttons to nonbold */
+    for (var child = $('halo-rendermode-'+id).firstChild;
+         child != null;
+         child = child.nextSibling) {
+            if (child.style) {
+                child.style.fontWeight = 'normal';
+            }
+    }
 
-    var e = Jifty.$('halo-inner-'+id);
-    if (!e.halo_rendered) {
-        e.halo_rendered = e.innerHTML;
-        jQuery(e).empty().append( jQuery('<div class="halo_source"></div>').text(e.halo_rendered) );
+    /* hide all the info divs */
+    $('halo-info-'+id).style.display = 'none';
+    for (var child = $('halo-info-'+id).firstChild;
+         child != null;
+         child = child.nextSibling) {
+            if (child.style) {
+                child.style.display = 'none';
+            }
     }
-}
 
-function halo_perl(id) {
-    halo_reset(id);
-    Jifty.$('halo-button-perl-'+id).style.fontWeight = 'bold';
-    Jifty.$('halo-inner-'+id).style.display   = 'none';
-    Jifty.$('halo-perl-'+id).style.display    = 'block';
+    /* restore the rendered div */
+    var e = $('halo-rendered-'+id);
+    e.style.display = 'block';
+    if (e.halo_rendered) {
+        e.innerHTML = e.halo_rendered;
+        e.halo_rendered = null;
+    }
 }
 
-function halo_reset(id) {
-    jQuery.each([
-            "button-perl", "button-source", "button-render", "inner", "perl"
-    ], function() {
-        jQuery("#halo-" + this + "-" + id).css({ 'font-weight': 'normal' });
-    });
+function remove_link(id, name) {
+    var link = $('halo-button-'+name+'-'+id);
+    var newlink = document.createElement("span");
+    newlink.appendChild(link.childNodes[0]);
+    link.parentNode.replaceChild(newlink, link);
 }
 

Modified: jifty/branches/jquery/share/web/static/js/jifty.js
==============================================================================
--- jifty/branches/jquery/share/web/static/js/jifty.js	(original)
+++ jifty/branches/jquery/share/web/static/js/jifty.js	Wed Feb  6 12:23:57 2008
@@ -772,7 +772,7 @@
     '.form_field .error, .form_field .warning, .form_field .canonicalization_note': function(e) {
         if ( e.innerHTML == "" ) jQuery(e).hide();
     },
-    '.-jifty-region-lazy': function(e) {
+    '.jifty-region-lazy': function(e) {
         var region = e.getAttribute("id").replace(/^region-/,"");
         Jifty.update( { 'fragments': [{'region': region, 'mode': 'Replace'}]}, e);
     }

Modified: jifty/branches/jquery/share/web/templates/__jifty/halo
==============================================================================
--- jifty/branches/jquery/share/web/templates/__jifty/halo	(original)
+++ jifty/branches/jquery/share/web/templates/__jifty/halo	Wed Feb  6 12:23:57 2008
@@ -1,6 +1,6 @@
 <div id="render_info">
-    <a href="#" onclick="draw_halos(); return false"><%_('Draw halos')%></a>
-    <a href="#" onclick="render_info_tree(); return false"><%_('Page info')%></a>
+    <a id="render_info-draw_halos" href="#" onclick="draw_halos(); return false"><%_('Draw halos')%></a>
+    <a id="render_info-page_info" href="#" onclick="render_info_tree(); return false"><%_('Page info')%></a>
 </div>
 <div style="display: none" id="render_info_tree">
 % foreach my $item (@stack) {

Modified: jifty/branches/jquery/share/web/templates/_elements/wrapper
==============================================================================
--- jifty/branches/jquery/share/web/templates/_elements/wrapper	(original)
+++ jifty/branches/jquery/share/web/templates/_elements/wrapper	Wed Feb  6 12:23:57 2008
@@ -16,6 +16,7 @@
   <& /_elements/keybindings &>
   </div>
   <div id="jifty-wait-message" style="display: none"><%_('Loading...')%></div>
+  <div id="jifty-result-popup"></div>
 % Jifty::Mason::Halo->render_component_tree() if (Jifty->config->framework('DevelMode') );
 %# This is required for jifty server push.  If you maintain your own
 %# wrapper, make sure you have this as well.

Modified: jifty/branches/jquery/t/01-dependencies.t
==============================================================================
--- jifty/branches/jquery/t/01-dependencies.t	(original)
+++ jifty/branches/jquery/t/01-dependencies.t	Wed Feb  6 12:23:57 2008
@@ -34,9 +34,9 @@
     $data =~ s/^=head.+?(^=cut|\Z)//gms;
 
     # look for use and use base statements
-    $used{$1}{$filename}++ while $data =~ /^\s*use\s+([\w:]+)/gm;
+    $used{$1}{$File::Find::name}++ while $data =~ /^\s*use\s+([\w:]+)/gm;
     while ($data =~ m|^\s*use base qw.([\w\s:]+)|gm) {
-        $used{$_}{$filename}++ for split ' ', $1;
+        $used{$_}{$File::Find::name}++ for split ' ', $1;
     }
 }
 

Modified: jifty/branches/jquery/t/03-form-protocol.t
==============================================================================
--- jifty/branches/jquery/t/03-form-protocol.t	(original)
+++ jifty/branches/jquery/t/03-form-protocol.t	Wed Feb  6 12:23:57 2008
@@ -26,6 +26,7 @@
   J:A:F-id-mymoniker: 23
   J:A:F-something-mymoniker: else
   J:ACTIONS: mymoniker
+template_arguments: {}
 fragments: {}
 === two actions
 --- form
@@ -64,6 +65,7 @@
   J:A:F-id-second: 42
   J:A:F-something-second: bla
   J:ACTIONS: mymoniker!second
+template_arguments: {}
 fragments: {}
 === two different actions
 --- form
@@ -102,6 +104,7 @@
   J:A:F-id-second: 42
   J:A:F-something-second: bla
   J:ACTIONS: mymoniker!second
+template_arguments: {}
 fragments: {}
 === ignore arguments without actions
 --- form
@@ -130,6 +133,7 @@
   J:A:F-id-second: 42
   J:A:F-something-second: bla
   J:ACTIONS: mymoniker!second
+template_arguments: {}
 fragments: {}
 === one active, one inactive action
 --- form
@@ -168,6 +172,7 @@
   J:A:F-id-second: 42
   J:A:F-something-second: bla
   J:ACTIONS: second
+template_arguments: {}
 fragments: {}
 === two actions, no J:ACTIONS
 --- form
@@ -204,6 +209,7 @@
   J:A-second: DoThat
   J:A:F-id-second: 42
   J:A:F-something-second: bla
+template_arguments: {}
 fragments: {}
 === ignore totally random stuff
 --- form
@@ -248,6 +254,7 @@
   J:A-second: DoThat
   J:A:F-id-second: 42
   J:A:F-something-second: bla
+template_arguments: {}
 fragments: {}
 === order doesn't matter
 --- form
@@ -284,6 +291,7 @@
   J:A-second: DoThat
   J:A:F-something-mymoniker: else
   J:A-mymoniker: DoSomething
+template_arguments: {}
 fragments: {}
 === fallbacks being ignored
 --- form
@@ -310,6 +318,7 @@
   J:A:F:F-id-mymoniker: 96
   J:A:F-something-mymoniker: else
   J:ACTIONS: mymoniker
+template_arguments: {}
 fragments: {}
 === fallbacks being ignored (other order)
 --- form
@@ -336,6 +345,7 @@
   J:A:F-id-mymoniker: 23
   J:A:F-something-mymoniker: else
   J:ACTIONS: mymoniker
+template_arguments: {}
 fragments: {}
 === fallbacks being used
 --- form
@@ -360,6 +370,7 @@
   J:A:F:F-id-mymoniker: 96
   J:A:F-something-mymoniker: else
   J:ACTIONS: mymoniker
+template_arguments: {}
 fragments: {}
 === two different actions, one with fallback, one without
 --- form
@@ -400,6 +411,7 @@
   J:A:F-id-second: 42
   J:A:F-something-second: feepy
   J:ACTIONS: mymoniker!second
+template_arguments: {}
 fragments: {}
 === just validating
 ---- form
@@ -441,4 +453,5 @@
   J:A:F-id-second: 42
   J:A:F-something-second: bla
   J:ACTIONS: mymoniker!second
+template_arguments: {}
 fragments: {}

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/Makefile.PL
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/Makefile.PL	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,7 @@
+use inc::Module::Install;
+
+name        'TestApp::Plugin::Attributes';
+version     '0.01';
+requires    'Jifty' => '0.71129';
+
+WriteAll;

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/bin/jifty
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/bin/jifty	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,11 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use File::Basename qw(dirname); 
+use UNIVERSAL::require;
+
+use Jifty;
+use Jifty::Script;
+
+local $SIG{INT} = sub { warn "Stopped\n"; exit; };
+Jifty::Script->dispatch();

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/etc/config.yml
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/etc/config.yml	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,76 @@
+--- 
+framework: 
+  AdminMode: 1
+  ApplicationClass: TestApp::Plugin::Attributes
+  ApplicationName: TestApp-Plugin-Attributes
+  ApplicationUUID: CCAA95B8-D400-11DC-990A-966E8CB3492A
+  ConfigFileVersion: 3
+  Database: 
+    AutoUpgrade: 1
+    CheckSchema: 1
+    Database: testapp_plugin_attributes
+    Driver: SQLite
+    Host: localhost
+    Password: ''
+    RecordBaseClass: Jifty::DBI::Record::Cachable
+    User: ''
+    Version: 0.0.1
+  DevelMode: 1
+  L10N: 
+    PoDir: share/po
+  LogLevel: INFO
+  Mailer: Sendmail
+  MailerArgs: []
+
+  Plugins: 
+    - 
+      LetMe: {}
+
+    - 
+      SkeletonApp: {}
+
+    - 
+      REST: {}
+
+    - 
+      Halo: {}
+
+    - 
+      ErrorTemplates: {}
+
+    - 
+      OnlineDocs: {}
+
+    - 
+      CompressedCSSandJS: {}
+
+    - 
+      AdminUI: {}
+
+    - 
+      Attributes: {}
+  PubSub: 
+    Backend: Memcached
+    Enable: ~
+  SkipAccessControl: 0
+  TemplateClass: TestApp::Plugin::Attributes::View
+  View: 
+    FallbackHandler: Jifty::View::Mason::Handler
+    Handlers: 
+      - Jifty::View::Static::Handler
+      - Jifty::View::Declare::Handler
+      - Jifty::View::Mason::Handler
+  Web: 
+    BaseURL: http://localhost
+    DataDir: var/mason
+    Globals: []
+
+    MasonConfig: 
+      autoflush: 0
+      default_escape_flags: h
+      error_format: text
+      error_mode: fatal
+    Port: 8888
+    ServeStaticFiles: 1
+    StaticRoot: share/web/static
+    TemplateRoot: share/web/templates

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Model/Song.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/lib/TestApp/Plugin/Attributes/Model/Song.pm	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,44 @@
+#!/usr/bin/env perl
+package TestApp::Plugin::Attributes::Model::Song;
+use strict;
+use warnings;
+
+use Jifty::Plugin::Attributes::Mixin::Attributes;
+use Jifty::DBI::Schema;
+use Jifty::Record schema {
+    column 'name' =>
+        type is 'text',
+        is mandatory;
+
+    column 'artist' =>
+        type is 'text',
+        is mandatory;
+
+    column 'album' =>
+        type is 'text',
+        is mandatory;
+};
+
+our %rights;
+
+sub current_user_can {
+    my $self = shift;
+    my $right = shift;
+    my %args = @_;
+
+    return $rights{$right} if exists $rights{$right};
+
+    $self->SUPER::current_user_can($right, @_);
+}
+
+sub set_right {
+    my $self = shift;
+    my $right = shift;
+    my $val = shift;
+
+    return delete $rights{$right} if !defined($val);
+    $rights{$right} = $val;
+}
+
+1;
+

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/00-basic.t
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/00-basic.t	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,46 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 12;
+
+my $song = TestApp::Plugin::Attributes::Model::Song->new;
+my ($ok, $msg) = $song->create(
+    name   => 'Arco Arena',
+    artist => 'Cake',
+    album  => 'Comfort Eagle',
+);
+ok($ok, $msg);
+
+can_ok($song, qw/attributes first_attribute add_attribute set_attribute delete_attribute/);
+
+is($song->first_attribute('instrumental'), undef, "unknown attributes return undef for ->first_attribute");
+
+my $attrs = $song->attributes;
+isa_ok($attrs, "Jifty::Plugin::Attributes::Model::AttributeCollection", "->attributes returns an AttributeCollection");
+can_ok($attrs, qw/named limit_to_object/);
+
+ok($song->set_attribute(
+    name        => 'is_instrumental',
+    description => 'Is this song an instrumental?',
+    content     => 1,
+));
+
+my $attr = $song->first_attribute('is_instrumental');
+can_ok($attr, qw/name description content object_type object_id object/);
+
+is($attr->name, 'is_instrumental', "name of the attribute was saved");
+is($attr->description,  'Is this song an instrumental?', "description of the attribute was saved");
+is($attr->content, 1, "content of the attribute was saved");
+
+my $song2 = TestApp::Plugin::Attributes::Model::Song->new;
+($ok, $msg) = $song2->create(
+    name   => 'A Passage to Bangkok',
+    artist => 'Rush',
+    album  => '2112',
+);
+ok($ok, $msg);
+
+ok(!defined($song2->first_attribute('is_instrumental')), "second song has no is_instrumental attribute");
+

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/01-content.t
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/01-content.t	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,46 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 7;
+
+my $song = TestApp::Plugin::Attributes::Model::Song->new;
+my ($ok, $msg) = $song->create(
+    name   => 'Home',
+    artist => 'Dream Theater',
+    album  => 'Scenes from a Memory',
+);
+ok($ok, $msg);
+
+$song->add_attribute(name => 'artists', content => [qw/LaBrie Myung Petrucci Portroy Rudess/]);
+is_deeply($song->first_attribute('artists')->content, [qw/LaBrie Myung Petrucci Portroy Rudess/], "attribute content can be an arrayref");
+
+$song->add_attribute(name => 'guests', content => {Thomason => "additional vocals", Brown => "hypnotherapist"});
+is_deeply($song->first_attribute('guests')->content, {Thomason => "additional vocals", Brown => "hypnotherapist"}, "attribute content can be a hashref");
+
+is($song->attributes->count, 2, "two attributes");
+is($song->attributes->named('artists')->count, 1, "one attribute named artists");
+is($song->attributes->named('guests')->count, 1, "one attribute named guests");
+
+my $complex = {
+    a => [qw/a b c/],
+    b => {
+        c => 'd',
+        e => [qw/f g h/],
+        i => {
+            j => 'k',
+            l => 'm',
+        },
+        n => [],
+    },
+    o => undef,
+};
+
+$song->add_attribute(
+    name => 'complex',
+    content => $complex,
+);
+
+is_deeply($song->first_attribute('complex')->content, $complex, "complex content can be saved");
+

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/02-crud-methods.t
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/02-crud-methods.t	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,53 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 8;
+
+my $song = TestApp::Plugin::Attributes::Model::Song->new;
+my ($ok, $msg) = $song->create(
+    name   => 'Backdrifts',
+    artist => 'Radiohead',
+    album  => 'Hail to the Thief',
+);
+ok($ok, $msg);
+
+$song->add("radiohead");
+$song->has_tags(qw/radiohead/);
+
+$song->add("2003");
+$song->has_tags(qw/radiohead 2003/);
+
+$song->set("httt");
+$song->has_tags(qw/httt/);
+
+$song->add("radiohead");
+$song->has_tags(qw/httt radiohead/);
+
+$song->add("2003");
+$song->has_tags(qw/httt radiohead 2003/);
+
+$song->delete_attribute('tag');
+$song->has_tags(qw//);
+
+$song->add("radiohead");
+$song->has_tags(qw/radiohead/);
+
+sub TestApp::Plugin::Attributes::Model::Song::add {
+    $_[0]->add_attribute(name => 'tag', content => $_[1]);
+}
+
+sub TestApp::Plugin::Attributes::Model::Song::set {
+    $_[0]->set_attribute(name => 'tag', content => $_[1]);
+}
+
+sub TestApp::Plugin::Attributes::Model::Song::has_tags {
+    my $self     = shift;
+    my %expected = map { $_ => 1 } @_;
+    my %got      = map { $_->content => 1 }
+                   @{ $self->attributes->named("tag")->items_array_ref };
+
+    ::is_deeply(\%got, \%expected, "attributes set correctly");
+}
+

Added: jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/03-permissions.t
==============================================================================
--- (empty file)
+++ jifty/branches/jquery/t/TestApp-Plugin-Attributes/t/03-permissions.t	Wed Feb  6 12:23:57 2008
@@ -0,0 +1,56 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 30;
+
+my $song = TestApp::Plugin::Attributes::Model::Song->new;
+my ($ok, $msg) = $song->create(
+    name   => 'Hysteria',
+    artist => 'Muse',
+    album  => 'Absolution',
+);
+ok($ok, $msg);
+
+ok($song->add_attribute(name => 'stars', content => 5), "can add attributes");
+my $attr = $song->first_attribute('stars');
+
+has_right($_) for qw/create read update delete/;
+
+$song->set_right(create => 0);
+has_right($_) for qw/create read update delete/;
+
+$song->set_right(delete => 0);
+has_right($_) for qw/create read update delete/;
+
+$song->set_right(update => 0);
+lacks_right($_, "$_ checks object's update right") for qw/create update delete/;
+has_right('read', "read checks object's read right");
+
+$song->set_right(read => 0);
+lacks_right($_) for qw/create read update delete/;
+
+$song->set_right(update => undef);
+has_right($_, "$_ checks object's update right") for qw/create update delete/;
+lacks_right('read', "read checks object's read right");
+
+$song->set_right(read => undef);
+has_right($_) for qw/create read update delete/;
+
+sub has_right {
+    my $right = shift;
+    my $has_right = $attr->current_user_can($right, object => $song);
+
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    ok($has_right, shift || "current_user_can $right");
+}
+
+sub lacks_right {
+    my $right = shift;
+    my $has_right = $attr->current_user_can($right, object => $song);
+
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    ok(!$has_right, shift || "current_user_cannot $right");
+}
+

Modified: jifty/branches/jquery/t/TestApp-Plugin-OAuth/lib/TestApp/Plugin/OAuth/Test.pm
==============================================================================
--- jifty/branches/jquery/t/TestApp-Plugin-OAuth/lib/TestApp/Plugin/OAuth/Test.pm	(original)
+++ jifty/branches/jquery/t/TestApp-Plugin-OAuth/lib/TestApp/Plugin/OAuth/Test.pm	Wed Feb  6 12:23:57 2008
@@ -49,6 +49,7 @@
         testname               => "",
         method                 => 'POST',
         token_secret           => '',
+        params_in              => 'method',
         @_,
     );
 
@@ -62,6 +63,7 @@
     my $code            = delete $params{code};
     my $testname        = delete $params{testname} || "Response was $code";
     my $method          = delete $params{method};
+    my $params_in       = delete $params{params_in};
     my $token_secret    = delete $params{token_secret};
     my $consumer_secret = delete $params{consumer_secret}
         or die "consumer_secret not passed to response_is!";
@@ -75,16 +77,23 @@
 
     my $r;
 
+    if ($params_in eq 'authz') {
+        $cmech->default_header("Authorization" => authz(%params));
+    }
+
     if ($method eq 'POST') {
-        $r = $cmech->post($url, [%params]);
+        $r = $cmech->post($url, $params_in eq 'method' ? [%params] : ());
     }
     else {
         my $query = join '&',
                     map { "$_=" . Jifty->web->escape_uri($params{$_}||'') }
                     keys %params;
-        $r = $cmech->get("$url?$query");
+        my $params = $params_in eq 'method' ? "?$query" : '';
+        $r = $cmech->get("$url$params");
     }
 
+    $cmech->default_headers->remove_header("Authorization");
+
     local $Test::Builder::Level = $Test::Builder::Level + 1;
     main::is($r->code, $code, $testname);
 
@@ -102,6 +111,16 @@
     return $cmech->content;
 }
 
+# creates an Authorization header
+sub authz {
+    my %params = @_;
+
+    return "OAuth "
+         . join ', ',
+             map { $_ . q{="} . Jifty->web->escape_uri($params{$_}) . q{"} }
+                keys %params;
+}
+
 sub sign {
     my ($method, $token_secret, $consumer_secret, %params) = @_;
 

Modified: jifty/branches/jquery/t/TestApp-Plugin-OAuth/t/02-request-token.t
==============================================================================
--- jifty/branches/jquery/t/TestApp-Plugin-OAuth/t/02-request-token.t	(original)
+++ jifty/branches/jquery/t/TestApp-Plugin-OAuth/t/02-request-token.t	Wed Feb  6 12:23:57 2008
@@ -5,7 +5,7 @@
 use Test::More;
 BEGIN {
     if (eval { require Net::OAuth::Request; require Crypt::OpenSSL::RSA; 1 }) {
-        plan tests => 58;
+        plan tests => 61;
     }
     else {
         plan skip_all => "Net::OAuth isn't installed";
@@ -69,6 +69,16 @@
     oauth_signature_method => 'RSA-SHA1',
 );
 # }}}
+# get a request token using authorization header {{{
+response_is(
+    code                   => 200,
+    testname               => "200 - Authorization header",
+    consumer_secret        => 'bar',
+    params_in              => 'authz',
+    oauth_consumer_key     => 'foo',
+    oauth_signature_method => 'HMAC-SHA1',
+);
+# }}}
 # same timestamp, different nonce {{{
 --$timestamp;
 response_is(

Modified: jifty/branches/jquery/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t
==============================================================================
--- jifty/branches/jquery/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t	(original)
+++ jifty/branches/jquery/t/TestApp-Plugin-PasswordAuth/t/00-model-User.t	Wed Feb  6 12:23:57 2008
@@ -11,7 +11,7 @@
 use lib 't/lib';
 use Jifty::SubTest;
 
-use Jifty::Test tests => 17;
+use Jifty::Test tests => 24;
 
 # Make sure we can load the model
 use_ok('TestApp::Plugin::PasswordAuth::Model::User');
@@ -68,3 +68,29 @@
                        password => 'secret');
 ok($id, "Created with grey");
 
+my ($res, $msg) = $r->set_password('foo');
+TODO: {
+local $TODO = 'huh?';
+ok(!$res, 'unable to set password shorter than 6');
+like($msg, qr/at least six/);
+ok($r->password_is('secret'), 'password not changed');
+};
+
+($id, $msg) = $r->create( name => 'jesse3',
+                          email => 'jrv2 at orz',
+                          color => 'gray',
+                          password => '',
+                          swallow_type => 'african' );
+
+ok(!$id, "Can't creaet without password");
+like($msg, qr/at least six/);
+
+($id, $msg) = $r->create( name => 'jesse3',
+                          email => 'jrv2 at orz',
+                          color => 'gray',
+                          password => '',
+                          swallow_type => 'african' );
+
+ok(!$id, "Can't create without password");
+like($msg, qr/at least six/);
+


More information about the Jifty-commit mailing list