| Jifty documentation | Contained in the Jifty distribution. |
Jifty::Plugin::Halo - Provides halos
This plugin provides http://seaside.st (Seasidesque) halos for your application. It's included by default when using Jifty with DevelMode turned on.
Only enable halos in DevelMode. Add our instrumentation to Template::Declare.
This is called to instrument Template::Declare templates. We also draw a halo around the template itself.
This will give you the halo header which includes links to the various information displays for this template.
Gives you a new frame for storing halo information.
Creates and pushes a frame onto the render stack. Mason's halos do not support arounding a component, so we fake it with an explicit stack.
This also triggers halo_pre_template for plugins adding halo data.
Pops a frame off the render stack. Mason's halos do not support
arounding a component, so we fake it with an explicit stack.
This also triggers halo_post_template for plugins adding halo data.
Returns true if the given FRAME should not have a halo around it.
| Jifty documentation | Contained in the Jifty distribution. |
use strict; use warnings; package Jifty::Plugin::Halo; use base qw/Jifty::Plugin/; use Time::HiRes 'time'; use Class::Trigger;
sub init { my $self = shift; return if $self->_pre_init; return unless Jifty->config->framework('DevelMode') && !Jifty->config->framework('HideHalos'); warn "Overwriting an existing Template::Declare->around_template" if Template::Declare->around_template; Template::Declare->around_template(sub { $self->around_template(@_) }); }
sub around_template { my ($self, $orig, $path, $args, $code) = @_; # for now, call the last piece of the template's path the name $path =~ m{.*/(.+)}; my $name = $1 || $path; 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 $proscribed = $self->is_proscribed($frame); Template::Declare->buffer->append($self->halo_header($frame)) unless $proscribed; $orig->(); $frame = $self->pop_frame; Template::Declare->buffer->append($self->halo_footer($frame)) unless $proscribed; }
sub halo_header { 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 $rendermode = '[ ' . join(' | ', @buttons) . ' ]'; return << " HEADER"; <div id="halo-$id" class="halo"> <div class="halo-header"> <span id="halo-rendermode-$id" class="halo-rendermode"> $rendermode </span> <div class="halo-name">$name</div> </div> <div id="halo-inner-$id"> <div id="halo-rendered-$id"> HEADER }
sub halo_footer { 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 = eval { defined $value && fileno($value) } ? '*GLOB*' : Jifty->web->escape( Jifty::YAML::Dump($value) ); $out .= qq{<a href="#" onclick="jQuery(Jifty.\$('$expanded')).toggle(); 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; }
sub is_proscribed { my ($self, $frame) = @_; return 1 if $frame->{'proscribed'}; $frame->{'proscribed'} = 1 unless Jifty->handler->stash->{'in_body'}; return $frame->{'proscribed'}? 1 : 0; } 1;