[Jifty-commit] jifty branch, master, updated. 1.10518-74-g8d11269

Jifty commits jifty-commit at lists.jifty.org
Sun Apr 8 01:11:58 EDT 2012


The branch, master has been updated
       via  8d112694f8741a8cb48017ce0e51d6ef141cd910 (commit)
       via  070c6eabd593db13921778aff863f39726c475cd (commit)
       via  be0fc130bfeb57d15d85dce2322b6bac279388f2 (commit)
       via  e66a1a8895dc4d2514089d85862dba8a5ddbbd1d (commit)
       via  d13267fcd9df8d4cbe175aec51706a7bbbb141a2 (commit)
      from  87dc2539994d2e99b1c509089c2016922a8a7e94 (commit)

Summary of changes:
 lib/Jifty.pm                                       |    8 +-
 lib/Jifty/Plugin.pm                                |   29 +--
 lib/Jifty/Plugin/Authentication/Password.pm        |   12 +-
 .../Password/Action/GeneratePasswordToken.pm       |   48 ++-
 .../Plugin/Authentication/Password/Dispatcher.pm   |   15 +-
 lib/Jifty/Plugin/Authentication/Password/View.pm   |   67 ++--
 lib/Jifty/Plugin/Halo.pm                           |   76 +++-
 .../{View/Mason/Halo.pm => Plugin/Halo/Mason.pm}   |   48 +---
 lib/Jifty/Plugin/ViewDeclarePage/Page.pm           |    4 +-
 lib/Jifty/View.pm                                  |    1 +
 lib/Jifty/View/Declare/Handler.pm                  |    9 +-
 lib/Jifty/View/Declare/Page.pm                     |    7 +-
 lib/Jifty/View/Mason/Handler.pm                    |    4 +-
 lib/Jifty/Web.pm                                   |    6 +-
 .../Authentication/Password/web/static/js/MD5.js   |  397 ++++++++++++++++++++
 .../Password/web/static/js/login_hashing.js        |   54 +++
 .../Jifty/Plugin/Halo/web/static/css/halo.css}     |    0
 .../Jifty/Plugin/Halo}/web/static/js/halo.js       |    0
 .../Jifty/Plugin/Halo}/web/templates/__jifty/halo  |    0
 share/web/static/css/main.css                      |    1 -
 share/web/templates/_elements/wrapper              |   14 +-
 21 files changed, 630 insertions(+), 170 deletions(-)
 rename lib/Jifty/{View/Mason/Halo.pm => Plugin/Halo/Mason.pm} (51%)
 create mode 100644 share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/MD5.js
 create mode 100644 share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/login_hashing.js
 rename share/{web/static/css/halos.css => plugins/Jifty/Plugin/Halo/web/static/css/halo.css} (100%)
 rename share/{ => plugins/Jifty/Plugin/Halo}/web/static/js/halo.js (100%)
 rename share/{ => plugins/Jifty/Plugin/Halo}/web/templates/__jifty/halo (100%)

- Log -----------------------------------------------------------------
commit d13267fcd9df8d4cbe175aec51706a7bbbb141a2
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Wed Mar 21 21:11:11 2012 -0400

    Add plugins one-at-a-time
    
    When the plugin's dispatcher is loaded, it can now assume that the
    plugin itself is in Jifty->plugins.  Using this, it can inspect the
    plugin's configuration, and alter which rules to add to the dispatcher
    accordingly.

diff --git a/lib/Jifty.pm b/lib/Jifty.pm
index 2df006b..0e91f97 100644
--- a/lib/Jifty.pm
+++ b/lib/Jifty.pm
@@ -174,7 +174,7 @@ sub new {
     Jifty->logger( Jifty::Logger->new( $args{'logger_component'} ) );
 
     # Set up plugins
-    my @plugins;
+    @PLUGINS = ();
     my @plugins_to_load = @{Jifty->config->framework('Plugins')};
     my $app_plugin = Jifty->app_class('Plugin');
     # we are pushing prereq to plugin, hence the 3-part for.
@@ -204,7 +204,7 @@ sub new {
             next if grep { $_ =~ $this_class } @plugins_to_load;
 
             # already loaded plugin objects
-            next if grep { ref($_) =~ $this_class } @plugins;
+            next if grep { ref($_) =~ $this_class } Jifty->plugins;
         }
 
         # Load the plugin options
@@ -217,15 +217,11 @@ sub new {
 
         # Initialize the plugin and mark the prerequisites for loading too
         my $plugin_obj = $class->new(%options);
-        push @plugins, $plugin_obj;
         foreach my $name ($plugin_obj->prereq_plugins) {
             push @plugins_to_load, {$name => {}, _prereq => 1};
         }
     }
 
-    # All plugins loaded, save them for later reference
-    Jifty->plugins(@plugins);
-
     # Now that we have the config set up and loaded plugins,
     # load the localization files.
     Jifty::I18N->refresh();
diff --git a/lib/Jifty/Plugin.pm b/lib/Jifty/Plugin.pm
index 98777c0..f409899 100644
--- a/lib/Jifty/Plugin.pm
+++ b/lib/Jifty/Plugin.pm
@@ -51,12 +51,14 @@ sub new {
     my $class = shift;
     my $self = $class->SUPER::new( { @_ });
 
-    # Get a classloader set up
-    Jifty::Util->require($class->dispatcher);
-
     # XXX TODO: Add .po path
     $self->init(@_);
 
+    Jifty->plugins( Jifty->plugins, $self );
+
+    # Pull in the dispatcher
+    Jifty::Util->require($class->dispatcher);
+
     # XXX: If we have methods for halos, add them. Some way of detecting "are
     # we going to be using halos" would be superb. As it stands right now,
     # plugins are loaded, initialized, and prereq-examined in the order they're

commit e66a1a8895dc4d2514089d85862dba8a5ddbbd1d
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Wed Mar 21 21:12:09 2012 -0400

    Make signup an optional part of the login plugin
    
    Some applications wish tighter control of users than simply allowing any
    user to register -- for them, the authentication plugin is still useful,
    but provides too leniant a route for user registration.

diff --git a/lib/Jifty/Plugin/Authentication/Password.pm b/lib/Jifty/Plugin/Authentication/Password.pm
index 8a6f0b2..1ae03e7 100644
--- a/lib/Jifty/Plugin/Authentication/Password.pm
+++ b/lib/Jifty/Plugin/Authentication/Password.pm
@@ -4,7 +4,7 @@ use warnings;
 package Jifty::Plugin::Authentication::Password;
 use base qw/Jifty::Plugin/;
 
-__PACKAGE__->mk_accessors(qw(nav_menu));
+__PACKAGE__->mk_accessors(qw(nav_menu signup));
 
 =head1 NAME
 
@@ -51,10 +51,14 @@ sub init {
     my $self = shift;
     return if $self->_pre_init;
 
-    my %opt  = ( nav_menu => 1,
-                 @_ );
+    my %opt  = (
+        nav_menu => 1,
+        signup   => 1,
+        @_
+    );
 
     $self->nav_menu( $opt{nav_menu} );
+    $self->signup( $opt{signup} );
 }
 
 =head1 SEE ALSO
diff --git a/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm b/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm
index 12e1293..7890a4c 100644
--- a/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm
+++ b/lib/Jifty/Plugin/Authentication/Password/Dispatcher.pm
@@ -4,6 +4,8 @@ use warnings;
 package Jifty::Plugin::Authentication::Password::Dispatcher;
 use Jifty::Dispatcher -base;
 
+my ($self) = Jifty->find_plugin('Jifty::Plugin::Authentication::Password');
+
 =head1 NAME
 
 Jifty::Plugin::Authentication::Password::Dispatcher - password plugin dispatcher
@@ -14,6 +16,12 @@ All the dispatcher rules jifty needs to support L<Jifty::Authentication::Passwor
 
 =head1 RULES
 
+=cut
+
+before '*' => run {
+    Jifty->api->hide( 'Signup' );
+} unless $self->signup;
+
 =head2 C<before logout>
 
 Logout and return home.
@@ -37,11 +45,6 @@ Setup the navigation menu for login or logout.
 =cut
 
 before '*' =>  run {
-    my ($ap) = Jifty->find_plugin('Jifty::Plugin::Authentication::Password')
-        or return;
-
-    return unless $ap->nav_menu;
-
     if ( Jifty->web->current_user->id ) {
         logged_in_nav();
     } else {
@@ -49,7 +52,7 @@ before '*' =>  run {
 
     }
 
-};
+} if $self->nav_menu;
 
 =head2 C<on qr/^(?:signup|lost_password)$/>
 
diff --git a/lib/Jifty/Plugin/Authentication/Password/View.pm b/lib/Jifty/Plugin/Authentication/Password/View.pm
index 60ca2cc..94d167e 100644
--- a/lib/Jifty/Plugin/Authentication/Password/View.pm
+++ b/lib/Jifty/Plugin/Authentication/Password/View.pm
@@ -15,6 +15,8 @@ password authentication plugin.
 package Jifty::Plugin::Authentication::Password::View;
 use Jifty::View::Declare -base;
 
+my ($self) = Jifty->find_plugin('Jifty::Plugin::Authentication::Password');
+
 =head1 TEMPLATES
 
 =head2 signup
@@ -23,20 +25,22 @@ Displays a sign-up form.
 
 =cut
 
-template 'signup' => page { title => _('Sign up') } content {
-    show 'signup_widget';
-};
-
-template 'signup_widget' => sub {
-    my ( $action, $next ) = get(qw(action next));
-    $action ||= new_action( class => 'Signup' );
-    $next ||= Jifty::Continuation->new( request => Jifty::Request->new(path => "/") );
-    Jifty->web->form->start( call => $next );
-    render_param( $action => 'name' , focus => 1);
-    render_param( $action => $_ ) for ( grep {$_ ne 'name'} $action->argument_names );
-    form_return( label => _('Sign up'), submit => $action );
-    Jifty->web->form->end();
-};
+if ($self->signup) {
+    template 'signup' => page { title => _('Sign up') } content {
+        show 'signup_widget';
+    };
+
+    template 'signup_widget' => sub {
+        my ( $action, $next ) = get(qw(action next));
+        $action ||= new_action( class => 'Signup' );
+        $next ||= Jifty::Continuation->new( request => Jifty::Request->new(path => "/") );
+        Jifty->web->form->start( call => $next );
+        render_param( $action => 'name' , focus => 1);
+        render_param( $action => $_ ) for ( grep {$_ ne 'name'} $action->argument_names );
+        form_return( label => _('Sign up'), submit => $action );
+        Jifty->web->form->end();
+    };
+}
 
 =head2 login
 
@@ -109,19 +113,6 @@ template 'let/reset_lost_password' => page { title => _('Reset lost password') }
     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("/");
-};
-
 =head2 lost_password
 
 Starts the process of sending a link to reset a lost password by email.
@@ -146,6 +137,19 @@ template 'lost_password' => page { title => 'Send a link to reset your password'
 
 };
 
+=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("/");
+};
+
 =head2 resend_confirmation
 
 Request a new email confirmation message be sent to your email account.

commit be0fc130bfeb57d15d85dce2322b6bac279388f2
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Fri Mar 23 02:01:04 2012 -0400

    Make password hashing work out-of-the-box with the login plugin
    
    The password authentication plugin included part of the mechanics to do
    client-side hashing of the password, but did not include the relevant
    client-side javascript, or make the GeneratePasswordToken sufficiently
    general.

diff --git a/lib/Jifty/Plugin/Authentication/Password.pm b/lib/Jifty/Plugin/Authentication/Password.pm
index 1ae03e7..f3334ff 100644
--- a/lib/Jifty/Plugin/Authentication/Password.pm
+++ b/lib/Jifty/Plugin/Authentication/Password.pm
@@ -6,6 +6,8 @@ use base qw/Jifty::Plugin/;
 
 __PACKAGE__->mk_accessors(qw(nav_menu signup));
 
+Jifty->web->add_javascript(qw/ MD5.js login_hashing.js /);
+
 =head1 NAME
 
 Jifty::Plugin::Authentication::Password - password authentication plugin
diff --git a/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm b/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm
index a773cf6..d00026c 100755
--- a/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm
+++ b/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm
@@ -10,6 +10,17 @@ Jifty::Plugin::Authentication::PasswordAction::GeneratePasswordToken - generate
 package Jifty::Plugin::Authentication::Password::Action::GeneratePasswordToken;
 use base qw/Jifty::Action/;
 
+__PACKAGE__->mk_accessors( 'login_by' );
+
+sub new {
+    my $class = shift;
+    my $self = $class->SUPER::new(@_);
+    my $plugin =
+        Jifty->find_plugin('Jifty::Plugin::Authentication::Password');
+    $self->login_by( $plugin->{login_by} || 'email' );
+    return $self;
+}
+
 =head2 arguments
 
 We need the email of the user we're fetching a token for, so we can
@@ -17,8 +28,9 @@ return the salt.
 
 =cut
 
-sub arguments { 
-    return( { email => { mandatory => 1 } });
+sub arguments {
+    my $self = shift;
+    return( { $self->login_by => { mandatory => 1 } });
 
 }
 
@@ -28,26 +40,38 @@ sub arguments {
 Generate a token and throw it back to the browser.  Also, return the
 user's password salt in $self->result->content.
 
-
 =cut
 
 sub take_action {
     my $self = shift;
 
-    my $email = $self->argument_value('email');
-    my $class = Jifty->app_class('Model','User');
-    my $user = $class->new(current_user => Jifty->app_class('CurrentUser')->superuser);
-    $user->load_by_cols(email => $email);
-    unless($user->id) {
-        $self->result->error('No such user');
-    }
-
+    my $user = $self->load_user( $self->argument_value( $self->login_by ) );
     my $password = $user->_value('password');
-    
+
     my $token = time();
     $self->result->content(token => $token);
     $self->result->content(salt  => ($password ? $password->[1] : ""));
     Jifty->web->session->set(login_token => $token);
 }
 
+=head2 load_user
+
+Load up and return a YourApp::User object for the user trying to log in
+
+=cut
+
+sub load_user {
+    my $self = shift;
+    my $value = shift;
+    my $user = Jifty->app_class('Model', 'User')->new(
+        current_user => Jifty->app_class('CurrentUser')->superuser
+    );
+
+    # normally we use name as column name instead of usernmae
+    my $column = $self->login_by eq 'username' ? 'name' : $self->login_by;
+    $user->load_by_cols( $column => $value );
+    return $user;
+
+}
+
 1;
diff --git a/lib/Jifty/Plugin/Authentication/Password/View.pm b/lib/Jifty/Plugin/Authentication/Password/View.pm
index 94d167e..0abc95a 100644
--- a/lib/Jifty/Plugin/Authentication/Password/View.pm
+++ b/lib/Jifty/Plugin/Authentication/Password/View.pm
@@ -66,6 +66,7 @@ template login_widget => sub {
 
     my ( $action, $next ) = get( 'action', 'next' );
     $action ||= new_action( class => 'Login' );
+    my $moniker = $action->moniker;
     $next ||= Jifty::Continuation->new(
         request => Jifty::Request->new( path => "/" ) );
     unless ( Jifty->web->current_user->id ) {
@@ -82,8 +83,12 @@ template login_widget => sub {
               } else {
                 render_param( $action, 'email', focus => 1 );
               };
-            render_param( $action, $_ ) for (qw(password remember));
-            form_return( label => _(q{Login}), submit => $action );
+            render_param( $action, $_ ) for (qw(password remember token hashed_password));
+            form_return(
+                label   => _(q{Login}),
+                submit  => $action,
+                onclick => "return getPasswordToken('$moniker');"
+            );
             hyperlink(
                 label => _("Lost your password?"),
                 url   => "/lost_password"
diff --git a/share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/MD5.js b/share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/MD5.js
new file mode 100644
index 0000000..b311682
--- /dev/null
+++ b/share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/MD5.js
@@ -0,0 +1,397 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+
+=head1 NAME
+
+Digest.MD5 - JavaScript Interface to the MD5 Algorithm
+
+=head1 SYNOPSIS
+
+    // Import From JSAN
+    JSAN.use('Digest.MD5', ':all');
+
+    var data   = "Hello you crazy cat!";
+
+    var digest    = md5(data);
+    var digestHex = md5Hex(data);
+    var digestB64 = md5Base64(data);
+
+=cut
+
+*/
+
+if (typeof Digest == 'undefined') var Digest = {};
+
+Digest.MD5 = function () {
+}
+
+Digest.MD5.VERSION = '0.01';
+
+Digest.MD5.EXPORT_OK   = [  'md5', 'md5Hex', 'md5Base64' ];
+Digest.MD5.EXPORT_TAGS = { ':all': Digest.MD5.EXPORT_OK };
+
+/*
+
+=head1 DESCRIPTON
+
+=head2 Functions
+
+=head3 md5()
+
+Returns an MD5 hash of the data passed to it.
+
+=head3 md5Hex()
+
+Returns a hex encoded MD5 hash of the data passed to it.
+
+=head3 md5Base64()
+
+Returns a base64 encoded MD5 hash of the data passed to it.
+
+=head2 Exporting
+
+To export all functions, use the C<:all> export tag.
+
+To export only a set of functions, name them explicitly
+on the C<JSAN.use()> call.
+
+  JSAN.use('Digest.MD5', 'md5Hex');
+
+=cut
+
+*/
+
+Digest.MD5.md5 = function (str) {
+    var md5 = new Digest.MD5();
+    return md5.str_md5(str);
+}
+
+Digest.MD5.md5Hex = function (str) {
+    var md5 = new Digest.MD5();
+    return md5.hex_md5(str);
+}
+
+Digest.MD5.md5Base64 = function (str) {
+    var md5 = new Digest.MD5();
+    return md5.b64_md5(str);
+}
+
+Digest.MD5.prototype = {
+    /*
+     * Configurable variables. You may need to tweak these to be compatible with
+     * the server-side, but the defaults work in most cases.
+     */
+    hexcase: 0,  /* hex output format. 0 - lowercase; 1 - uppercase        */
+    b64pad:  "", /* base-64 pad character. "=" for strict RFC compliance   */
+    chrsz:   8,  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+    
+    /*
+     * These are the functions you'll usually want to call
+     * They take string arguments and return either hex or base-64 encoded strings
+     */
+    hex_md5: function (s) {
+        return this.binl2hex(
+            this.core_md5(
+                this.str2binl(s),
+                s.length * this.chrsz
+            )
+        );
+    },
+    b64_md5: function (s) {
+        return this.binl2b64(
+            this.core_md5(
+                this.str2binl(s),
+                s.length * this.chrsz
+            )
+        );
+    },
+    str_md5: function (s) {
+        return this.binl2str(
+            this.core_md5(
+                this.str2binl(s),
+                s.length * this.chrsz
+            )
+        );
+    },
+    hex_hmac_md5: function (key, data) {
+        return this.binl2hex(
+            this.core_hmac_md5(key, data)
+        );
+    },
+    b64_hmac_md5: function (key, data) {
+        return this.binl2b64(
+            this.core_hmac_md5(key, data)
+        );
+    },
+    str_hmac_md5: function (key, data) {
+        return this.binl2str(
+            this.core_hmac_md5(key, data)
+        );
+    },
+    
+    /*
+     * Perform a simple self-test to see if the VM is working
+     */
+    md5_vm_test: function () {
+        return this.hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
+    },
+    
+    /*
+     * Calculate the MD5 of an array of little-endian words, and a bit length
+     */
+    core_md5: function (x, len) {
+        /* append padding */
+        x[len >> 5] |= 0x80 << ((len) % 32);
+        x[(((len + 64) >>> 9) << 4) + 14] = len;
+        
+        var a =  1732584193;
+        var b = -271733879;
+        var c = -1732584194;
+        var d =  271733878;
+        
+        for(var i = 0; i < x.length; i += 16)
+        {
+            var olda = a;
+            var oldb = b;
+            var oldc = c;
+            var oldd = d;
+        
+            a = this.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+            d = this.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+            c = this.md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
+            b = this.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+            a = this.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+            d = this.md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
+            c = this.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+            b = this.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+            a = this.md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
+            d = this.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+            c = this.md5_ff(c, d, a, b, x[i+10], 17, -42063);
+            b = this.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+            a = this.md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
+            d = this.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+            c = this.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+            b = this.md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
+        
+            a = this.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+            d = this.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+            c = this.md5_gg(c, d, a, b, x[i+11], 14,  643717713);
+            b = this.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+            a = this.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+            d = this.md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
+            c = this.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+            b = this.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+            a = this.md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
+            d = this.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+            c = this.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+            b = this.md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
+            a = this.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+            d = this.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+            c = this.md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
+            b = this.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+        
+            a = this.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+            d = this.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+            c = this.md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
+            b = this.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+            a = this.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+            d = this.md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
+            c = this.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+            b = this.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+            a = this.md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
+            d = this.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+            c = this.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+            b = this.md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+            a = this.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+            d = this.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+            c = this.md5_hh(c, d, a, b, x[i+15], 16,  530742520);
+            b = this.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+        
+            a = this.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+            d = this.md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
+            c = this.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+            b = this.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+            a = this.md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
+            d = this.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+            c = this.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+            b = this.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+            a = this.md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
+            d = this.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+            c = this.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+            b = this.md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
+            a = this.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+            d = this.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+            c = this.md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
+            b = this.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+        
+            a = this.safe_add(a, olda);
+            b = this.safe_add(b, oldb);
+            c = this.safe_add(c, oldc);
+            d = this.safe_add(d, oldd);
+        }
+        return Array(a, b, c, d);
+        
+    },
+    
+    /*
+     * These functions implement the four basic operations the algorithm uses.
+     */
+    md5_cmn: function (q, a, b, x, s, t) {
+        return this.safe_add(
+            this.bit_rol(
+                this.safe_add(
+                    this.safe_add(a, q),
+                    this.safe_add(x, t)
+                ),
+                s
+            ),
+            b
+        );
+    },
+    md5_ff: function (a, b, c, d, x, s, t) {
+        return this.md5_cmn(
+            (b & c) | ((~b) & d), a, b, x, s, t
+        );
+    },
+    md5_gg: function (a, b, c, d, x, s, t) {
+        return this.md5_cmn(
+            (b & d) | (c & (~d)), a, b, x, s, t
+        );
+    },
+    md5_hh: function (a, b, c, d, x, s, t) {
+        return this.md5_cmn(
+            b ^ c ^ d, a, b, x, s, t
+        );
+    },
+    md5_ii: function (a, b, c, d, x, s, t) {
+        return this.md5_cmn(
+            c ^ (b | (~d)), a, b, x, s, t
+        );
+    },
+    
+    /*
+     * Calculate the HMAC-MD5, of a key and some data
+     */
+    core_hmac_md5: function (key, data) {
+        var bkey = this.str2binl(key);
+        if(bkey.length > 16) bkey = this.core_md5(bkey, key.length * this.chrsz);
+        
+        var ipad = Array(16), opad = Array(16);
+        for(var i = 0; i < 16; i++)
+        {
+            ipad[i] = bkey[i] ^ 0x36363636;
+            opad[i] = bkey[i] ^ 0x5C5C5C5C;
+        }
+        
+        var hash = this.core_md5(
+            ipad.concat(
+                this.str2binl(data)
+            ),
+            512 + data.length * this.chrsz
+        );
+        return this.core_md5(opad.concat(hash), 512 + 128);
+    },
+    
+    /*
+     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+     * to work around bugs in some JS interpreters.
+     */
+    safe_add: function (x, y) {
+        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+        return (msw << 16) | (lsw & 0xFFFF);
+    },
+    
+    /*
+     * Bitwise rotate a 32-bit number to the left.
+     */
+    bit_rol: function (num, cnt) {
+        return (num << cnt) | (num >>> (32 - cnt));
+    },
+    
+    /*
+     * Convert a string to an array of little-endian words
+     * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+     */
+    str2binl: function (str) {
+        var bin = Array();
+        var mask = (1 << this.chrsz) - 1;
+        for(var i = 0; i < str.length * this.chrsz; i += this.chrsz)
+            bin[i>>5] |= (str.charCodeAt(i / this.chrsz) & mask) << (i%32);
+        return bin;
+    },
+    
+    /*
+     * Convert an array of little-endian words to a string
+     */
+    binl2str: function (bin) {
+        var str = "";
+        var mask = (1 << this.chrsz) - 1;
+        for(var i = 0; i < bin.length * 32; i += this.chrsz)
+            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
+        return str;
+    },
+    
+    /*
+     * Convert an array of little-endian words to a hex string.
+     */
+    binl2hex: function (binarray) {
+        var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+        var str = "";
+        for(var i = 0; i < binarray.length * 4; i++)
+        {
+            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
+                   hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
+        }
+        return str;
+    },
+    
+    /*
+     * Convert an array of little-endian words to a base-64 string
+     */
+    binl2b64: function (binarray) {
+        var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        var str = "";
+        for(var i = 0; i < binarray.length * 4; i += 3)
+        {
+            var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
+                        | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
+                        |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
+            for(var j = 0; j < 4; j++)
+            {
+                if(i * 8 + j * 6 > binarray.length * 32) str += this.b64pad;
+                else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+            }
+        }
+        return str;
+    }
+    
+};
+
+/*
+
+=head1 SEE ALSO
+
+L<JSAN>.
+
+=head1 AUTHOR
+
+Casey West, <F<casey at geeknest.com>>.
+
+=head1 COPYRIGHT
+
+  Copyright (c) 2005 Casey West.  All rights reserved.
+  This module is free software; you can redistribute it and/or modify it
+  under the terms of the Artistic license.
+
+=cut
+
+*/
diff --git a/share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/login_hashing.js b/share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/login_hashing.js
new file mode 100644
index 0000000..3bfa175
--- /dev/null
+++ b/share/plugins/Jifty/Plugin/Authentication/Password/web/static/js/login_hashing.js
@@ -0,0 +1,54 @@
+function getPasswordToken(moniker) {
+    var url = "/__jifty/webservices/xml";
+
+    var action = new Action(moniker);
+    var token_field = action.getField("token");
+    var hashedpw_field = action.getField("hashed_password");
+
+    if (!token_field || !hashedpw_field)
+        return true;
+
+    var parseToken = function(request, responseStatus) {
+        var myform    = action.form;
+
+        var response  = request.documentElement;
+        var token     = response.getElementsByTagName("token")[0].firstChild.nodeValue;
+        var salt      = response.getElementsByTagName("salt")[0].firstChild;
+        if (!salt)
+            return;
+        salt          = salt.nodeValue;
+
+        if (token != "") {  // don't hash passwords if no token
+            var password_field = action.getField("password");
+            var password = password_field.value;
+            hashedpw_field.value = Digest.MD5.md5Hex(token + " " + Digest.MD5.md5Hex(password + salt));
+            token_field.value = token;
+
+            // Clear password so it won't get submitted in cleartext.
+            password_field.value = "";
+        }
+        myform.submit();
+    };
+
+    var request = { path: url, actions: {} };
+    var a = {};
+    a["moniker"] = "login";
+    a["class"]   = "GeneratePasswordToken";
+    a["fields"]  = {};
+    if (action.getField("username"))
+        a["fields"]["username"]  = action.getField("username").value;
+    if (action.getField("email"))
+        a["fields"]["email"]     = action.getField("email").value;
+    request["actions"]["login"] = a;
+
+    jQuery.ajax({
+        url: url,
+        type: "post",
+        data: JSON.stringify(request),
+        contentType: 'text/x-json',
+        dataType: 'xml',
+        success: parseToken
+    });
+
+    return false;
+}

commit 070c6eabd593db13921778aff863f39726c475cd
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Apr 8 00:23:20 2012 -0400

    Allow Jifty->web->render_template to take a hashref of args to render with
    
    This allows simpler view-independent rendering of components.

diff --git a/lib/Jifty/View/Declare/Handler.pm b/lib/Jifty/View/Declare/Handler.pm
index 153e058..d0460f6 100644
--- a/lib/Jifty/View/Declare/Handler.pm
+++ b/lib/Jifty/View/Declare/Handler.pm
@@ -71,10 +71,17 @@ then print to STDOUT
 sub show {
     my $self     = shift;
     my $template = shift;
+    my $args     = shift;
 
     Template::Declare->buffer( Jifty->handler->buffer );
     eval {
-        Template::Declare::Tags::show_page( $template, { %{Jifty->web->request->arguments}, %{Jifty->web->request->template_arguments || {}} } );
+        Template::Declare::Tags::show_page(
+            $template,
+            $args || {
+                %{Jifty->web->request->arguments},
+                %{Jifty->web->request->template_arguments || {}},
+            },
+        } );
     };
     if (my $err = $@) {
         $err->rethrow if ref $err;
diff --git a/lib/Jifty/Web.pm b/lib/Jifty/Web.pm
index f2d03cd..53901e3 100644
--- a/lib/Jifty/Web.pm
+++ b/lib/Jifty/Web.pm
@@ -951,7 +951,7 @@ sub template_exists {
 
 my %TEMPLATE_CACHE;
 
-=head2 render_template PATH
+=head2 render_template PATH, [ARGS]
 
 Use our templating system to render a template.  Searches through
 L<Jifty::Handler/view_handlers> to find the first handler which
@@ -966,6 +966,7 @@ C</errors/404> if the template cannot be found.
 sub render_template {
     my $self     = shift;
     my $template = shift;
+    my $args     = shift;
     my $handler;
     my $content;
         my $void_context = ( defined wantarray ? 0 :1);
@@ -1004,7 +1005,7 @@ sub render_template {
     Jifty->handler->buffer->push( private => 1 ) unless $void_context;
 
     Jifty->handler->call_trigger("before_render_template", $handler, $template);
-    eval { $handler->show($template) };
+    eval { $handler->show($template, $args) };
 
     # Handle parse errors
     my $err = $@;

commit 8d112694f8741a8cb48017ce0e51d6ef141cd910
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Apr 8 00:24:59 2012 -0400

    Factor out all Halo logic into a standalone plugin
    
    This significantly simplifies core Jifty logic, as well as adding useful
    hooks (at the start and end of the body, for instance) for other plugins
    to use.
    
    In the process, fix halos to at least render on both HTML::Mason and
    Template::Declare rendering engines.

diff --git a/lib/Jifty/Plugin.pm b/lib/Jifty/Plugin.pm
index f409899..9063665 100644
--- a/lib/Jifty/Plugin.pm
+++ b/lib/Jifty/Plugin.pm
@@ -59,31 +59,6 @@ sub new {
     # Pull in the dispatcher
     Jifty::Util->require($class->dispatcher);
 
-    # XXX: If we have methods for halos, add them. Some way of detecting "are
-    # we going to be using halos" would be superb. As it stands right now,
-    # plugins are loaded, initialized, and prereq-examined in the order they're
-    # listed in the config files. Instead, each phase should be separate.
-    Jifty::Util->require("Jifty::Plugin::Halo");
-    Jifty::Util->require("Jifty::View::Mason::Halo");
-
-    if ($self->can('halo_pre_template')) {
-        Jifty::Plugin::Halo->add_trigger(
-            halo_pre_template => sub { $self->halo_pre_template(@_) },
-        );
-        Jifty::View::Mason::Halo->add_trigger(
-            halo_pre_template => sub { $self->halo_pre_template(@_) },
-        );
-    }
-
-    if ($self->can('halo_post_template')) {
-        Jifty::Plugin::Halo->add_trigger(
-            halo_post_template => sub { $self->halo_post_template(@_) },
-        );
-        Jifty::View::Mason::Halo->add_trigger(
-            halo_post_template => sub { $self->halo_post_template(@_) },
-        );
-    }
-
     return $self;
 }
 
diff --git a/lib/Jifty/Plugin/Halo.pm b/lib/Jifty/Plugin/Halo.pm
index 45ef817..7c02192 100644
--- a/lib/Jifty/Plugin/Halo.pm
+++ b/lib/Jifty/Plugin/Halo.pm
@@ -2,6 +2,7 @@ use strict;
 use warnings;
 
 package Jifty::Plugin::Halo;
+use Jifty::Plugin::Halo::Mason;
 use base qw/Jifty::Plugin/;
 use Time::HiRes 'time';
 use Class::Trigger;
@@ -12,7 +13,7 @@ Jifty::Plugin::Halo - Provides halos
 
 =head1 DESCRIPTION
 
-This plugin provides L<http://seaside.st|Seasidesque> halos for your
+This plugin provides L<http://seaside.st|Seaside>-esque halos for your
 application. It's included by default when using Jifty with DevelMode
 turned on.
 
@@ -28,13 +29,39 @@ L<Template::Declare>.
 sub init {
     my $self = shift;
     return if $self->_pre_init;
-    return unless Jifty->config->framework('DevelMode')
-               && !Jifty->config->framework('HideHalos');
+    return unless Jifty->config->framework('DevelMode');
+
+    Jifty->web->add_javascript( 'halo.js' );
+    Jifty->web->add_css( 'halo.css' );
 
     warn "Overwriting an existing Template::Declare->around_template"
         if Template::Declare->around_template;
-
     Template::Declare->around_template(sub { $self->around_template(@_) });
+
+    push @{ Jifty->config->framework('Web')->{'MasonConfig'}{plugins} },
+        'Jifty::Plugin::Halo::Mason';
+    Jifty::View->add_trigger( body_start => sub { $self->body_start } );
+    Jifty::View->add_trigger( body_end => sub { $self->body_end } );
+
+    Jifty->add_trigger( post_init => sub { $self->find_halo_plugins } );
+}
+
+=head2 find_halo_plugins
+
+Finds plugins which have C<halo_pre_template> or C<halo_post_template>
+methods, and adds them as callbacks in the requisite places.
+
+=cut
+
+sub find_halo_plugins {
+    my $self = shift;
+    for my $plugin (Jifty->plugins) {
+        for my $cb (grep {$plugin->can($_)} qw/ halo_pre_template halo_post_template/ ) {
+            Jifty::Plugin::Halo->add_trigger(
+                $cb => sub { $plugin->$cb(@_) },
+            );
+        }
+    }
 }
 
 =head2 around_template
@@ -67,15 +94,11 @@ sub around_template {
             Jifty->web->escape($deparsed);
         },
     };
-    my $proscribed = $self->is_proscribed($frame);
 
-    Template::Declare->buffer->append($self->halo_header($frame))
-        unless $proscribed;
+    Template::Declare->buffer->append($self->halo_header($frame));
     $orig->();
-
     $frame = $self->pop_frame;
-    Template::Declare->buffer->append($self->halo_footer($frame))
-        unless $proscribed;
+    Template::Declare->buffer->append($self->halo_footer($frame));
 }
 
 =head2 halo_header frame -> string
@@ -224,7 +247,6 @@ sub new_frame {
         id           => Jifty->web->serial,
         start_time   => time,
         subcomponent => 0,
-        proscribed   => 0,
         displays     => {
             R => { name => "render", default => 1 },
             S => { name => "source" },
@@ -291,19 +313,35 @@ sub pop_frame {
     return $frame;
 }
 
-=head2 is_proscribed FRAME
+sub body_start {
+    my $self = shift;
+    Jifty->handler->stash->{'in_body'} = 1;
+}
 
-Returns true if the given C<FRAME> should not have a halo around it.
+sub body_end {
+    my $self = shift;
+    Jifty->handler->stash->{'in_body'} = 0;
+    $self->render_component_tree;
+}
 
-=cut
+=head2 render_component_tree
 
-sub is_proscribed {
-    my ($self, $frame) = @_;
-    return 1 if $frame->{'proscribed'};
+Once we're just about to finish rendering our HTML page (just before
+the C<</body>> tag, we should call render_component_tree to output all
+the halo data and metadata.
 
-    $frame->{'proscribed'} = 1 unless Jifty->handler->stash->{'in_body'};
+=cut
 
-    return $frame->{'proscribed'}? 1 : 0;
+sub render_component_tree {
+    my $self  = shift;
+    my @stack = @{ Jifty->handler->stash->{'_halo_stack'} };
+
+    for (@stack) {
+        $_->{'render_time'} = int((($_->{'end_time'}||time) - $_->{'start_time'}) * 1000)/1000
+          unless defined $_->{'render_time'};
+    }
+    Jifty->web->render_template("/__jifty/halo", {stack => \@stack} );
+    return 1;
 }
 
 1;
diff --git a/lib/Jifty/View/Mason/Halo.pm b/lib/Jifty/Plugin/Halo/Mason.pm
similarity index 51%
rename from lib/Jifty/View/Mason/Halo.pm
rename to lib/Jifty/Plugin/Halo/Mason.pm
index de4f6d2..bafad59 100644
--- a/lib/Jifty/View/Mason/Halo.pm
+++ b/lib/Jifty/Plugin/Halo/Mason.pm
@@ -1,6 +1,6 @@
 use warnings;
 use strict;
-package Jifty::View::Mason::Halo;
+package Jifty::Plugin::Halo::Mason;
 use base qw/HTML::Mason::Plugin/;
 use Time::HiRes 'time';
 use Class::Trigger;
@@ -26,17 +26,15 @@ sub start_component_hook {
     my $context = shift;
 
     return if ($context->comp->path || '') eq "/__jifty/halo";
+    return unless Jifty->handler->stash->{'in_body'};
+    return if $context->comp->is_subcomp;
 
     my $frame = Jifty::Plugin::Halo->push_frame(
         args         => [map { eval { defined $_ and fileno( $_ ) }  ? "*GLOB*" : $_} @{$context->args}],
         path         => $context->comp->path || '',
-        subcomponent => $context->comp->is_subcomp() ? 1 : 0,
         name         => $context->comp->name || '(Unnamed component)',
-        proscribed   => $self->_unrendered_component($context) ? 1 : 0,
     );
 
-    return if Jifty::Plugin::Halo->is_proscribed( $frame );
-
     $context->request->out(Jifty::Plugin::Halo->halo_header($frame));
 }
 
@@ -52,47 +50,11 @@ sub end_component_hook {
     my $context = shift;
 
     return if ($context->comp->path || '') eq "/__jifty/halo";
+    return unless Jifty->handler->stash->{'in_body'};
+    return if $context->comp->is_subcomp;
 
     my $frame = Jifty::Plugin::Halo->pop_frame;
-    return if Jifty::Plugin::Halo->is_proscribed( $frame );
     $context->request->out(Jifty::Plugin::Halo->halo_footer($frame));
 }
 
-=head2 _unrendered_component CONTEXT
-
-Returns true if we're not currently inside the "Body" section of the
-webpage OR the current component is a subcomponent. (Rendering halos
-for subcomponents being too "heavy")
-
-=cut
-
-sub _unrendered_component {
-    my $self    = shift;
-    my $context = shift;
-    return $context->comp->is_subcomp ? 1 : 0; 
-}
-
-=head2 render_component_tree
-
-Once we're just about to finish rendering our HTML page (just before
-the C<</body>> tag, we should call render_component_tree to output all
-the halo data and metadata.
-
-=cut
-
-sub render_component_tree {
-    my $self  = shift;
-    return if Jifty->config->framework('HideHalos');
-
-    my @stack = @{ Jifty->handler->stash->{'_halo_stack'} };
-
-    for (@stack) {
-        $_->{'render_time'} = int((($_->{'end_time'}||time) - $_->{'start_time'}) * 1000)/1000
-          unless defined $_->{'render_time'};
-    }
-
-    Jifty->web->mason->comp("/__jifty/halo", stack => \@stack );
-}
-
-
 1;
diff --git a/lib/Jifty/Plugin/ViewDeclarePage/Page.pm b/lib/Jifty/Plugin/ViewDeclarePage/Page.pm
index aaa0c6c..eb2c83b 100644
--- a/lib/Jifty/Plugin/ViewDeclarePage/Page.pm
+++ b/lib/Jifty/Plugin/ViewDeclarePage/Page.pm
@@ -296,9 +296,9 @@ target for subclassing instead of this.
 sub render_body {
     my $self = shift;
     body {
-        Jifty->handler->stash->{'in_body'} = 1;
+        Jifty::View->call_trigger('body_start');
         $self->render_page;
-        Jifty->handler->stash->{'in_body'} = 0;
+        Jifty::View->call_trigger('body_end');
     };
     return '';
 }
diff --git a/lib/Jifty/View.pm b/lib/Jifty/View.pm
index 1880b10..42ff691 100644
--- a/lib/Jifty/View.pm
+++ b/lib/Jifty/View.pm
@@ -3,6 +3,7 @@ use strict;
 use warnings;
 
 use base qw/Jifty::Object/;
+use Class::Trigger;
 
 use Encode ();
 
diff --git a/lib/Jifty/View/Declare/Page.pm b/lib/Jifty/View/Declare/Page.pm
index 81364e7..b10ddcf 100644
--- a/lib/Jifty/View/Declare/Page.pm
+++ b/lib/Jifty/View/Declare/Page.pm
@@ -85,9 +85,9 @@ sub render_body {
     my ($self, $body_code) = @_;
 
     body {
-        Jifty->handler->stash->{'in_body'} = 1;
+        Jifty::View->call_trigger('body_start');
         $body_code->();
-        Jifty->handler->stash->{'in_body'} = 0;
+        Jifty::View->call_trigger('body_end');
     };
 }
 
@@ -225,10 +225,7 @@ sub _render_header {
     my $title = shift || '';
     $title =~ s/<.*?>//g;    # remove html
     HTML::Entities::decode_entities($title);
-    my $old = Jifty->handler->stash->{'in_body'};
-    Jifty->handler->stash->{'in_body'} = 0;
     with( title => $title ), show('/header');
-    Jifty->handler->stash->{'in_body'} = $old;
 }
 
 1;
diff --git a/lib/Jifty/View/Mason/Handler.pm b/lib/Jifty/View/Mason/Handler.pm
index ebb1c0e..9a08652 100644
--- a/lib/Jifty/View/Mason/Handler.pm
+++ b/lib/Jifty/View/Mason/Handler.pm
@@ -112,10 +112,8 @@ sub config {
     }
     push @{$config{comp_root}}, [jifty => Jifty::Util->absolute_path( Jifty->config->framework('Web')->{'DefaultTemplateRoot'})];
 
-    # In developer mode, we want halos, refreshing and all that other good stuff. 
+    # In developer mode, we want refreshing and all that other good stuff.
     if (Jifty->config->framework('DevelMode') ) {
-        push @{$config{'plugins'}}, 'Jifty::View::Mason::Halo'
-            unless Jifty->config->framework('HideHalos');
         $config{static_source}    = 0;
         $config{use_object_files} = 0;
     }
diff --git a/lib/Jifty/Web.pm b/lib/Jifty/Web.pm
index 53901e3..9892af7 100644
--- a/lib/Jifty/Web.pm
+++ b/lib/Jifty/Web.pm
@@ -46,7 +46,6 @@ __PACKAGE__->javascript_libs([qw(
     calendar.js
     datetime.js
     dom-drag.js
-    halo.js
     combobox.js
     key_bindings.js
     context_menu.js
diff --git a/share/web/static/css/halos.css b/share/plugins/Jifty/Plugin/Halo/web/static/css/halo.css
similarity index 100%
rename from share/web/static/css/halos.css
rename to share/plugins/Jifty/Plugin/Halo/web/static/css/halo.css
diff --git a/share/web/static/js/halo.js b/share/plugins/Jifty/Plugin/Halo/web/static/js/halo.js
similarity index 100%
rename from share/web/static/js/halo.js
rename to share/plugins/Jifty/Plugin/Halo/web/static/js/halo.js
diff --git a/share/web/templates/__jifty/halo b/share/plugins/Jifty/Plugin/Halo/web/templates/__jifty/halo
similarity index 100%
rename from share/web/templates/__jifty/halo
rename to share/plugins/Jifty/Plugin/Halo/web/templates/__jifty/halo
diff --git a/share/web/static/css/main.css b/share/web/static/css/main.css
index 3ad1e2d..8410070 100644
--- a/share/web/static/css/main.css
+++ b/share/web/static/css/main.css
@@ -7,7 +7,6 @@
 @import "keybindings.css";
 @import "forms.css";
 @import "crud.css";
- at import "halos.css";
 @import "app.css";
 @import "autocomplete.css";
 @import "yui/calendar/calendar-core.css";
diff --git a/share/web/templates/_elements/wrapper b/share/web/templates/_elements/wrapper
index c9ebd04..51e5170 100644
--- a/share/web/templates/_elements/wrapper
+++ b/share/web/templates/_elements/wrapper
@@ -1,4 +1,6 @@
+<& header, title => $title &>
 <body>
+% Jifty::View->call_trigger('body_start');
   <div id="headers">
     <%Jifty->web->link( url => "/", label => _(Jifty->config->framework('ApplicationName')))%>
     <h1 class="title"><% _($title) %></h1>
@@ -16,22 +18,12 @@
   <& /_elements/keybindings &>
   </div>
   <div id="jifty-wait-message" style="display: none"><%_('Loading...')%></div>
-% Jifty::View::Mason::Halo->render_component_tree() if Jifty->config->framework('DevelMode') && !Jifty->config->framework('HideHalos');
-%# This is required for jifty server push.  If you maintain your own
-%# wrapper, make sure you have this as well.
+% Jifty::View->call_trigger('body_end');
 % if ( Jifty->config->framework('PubSub')->{'Enable'} && Jifty::Subs->list ) {
 <script>new Jifty.Subs({}).start();</script>
 % }
 </body>
 </html>
-% Jifty->handler->stash->{'in_body'} = 0;
 <%args>
 $title => ""
 </%args>
-<%init>
-# First we set up the header. 
-$m->comp( 'header', title => $title);
-# now that we've printed out the header, we're inside the body, so it's safe to print
-# halo markers.
-Jifty->handler->stash->{'in_body'} = 1;
-</%init>

-----------------------------------------------------------------------


More information about the Jifty-commit mailing list