[Jifty-commit] r6116 - in jifty/trunk/plugins/ViewDeclarePage: . lib lib/Jifty lib/Jifty/Plugin/ViewDeclarePage
Jifty commits
jifty-commit at lists.jifty.org
Mon Dec 15 10:27:38 EST 2008
Author: ruz
Date: Mon Dec 15 10:27:38 2008
New Revision: 6116
Added:
jifty/trunk/plugins/ViewDeclarePage/Makefile.PL
jifty/trunk/plugins/ViewDeclarePage/lib/
jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/
jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/
jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage/
jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage.pm
jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage/Page.pm
Log:
* actually add ViewDeclarePage plugin that you gonna love :) that was some svk misuse
Added: jifty/trunk/plugins/ViewDeclarePage/Makefile.PL
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/ViewDeclarePage/Makefile.PL Mon Dec 15 10:27:38 2008
@@ -0,0 +1,8 @@
+use inc::Module::Install 0.46;
+
+name 'Jifty-Plugin-ViewDeclarePage';
+all_from 'lib/Jifty/Plugin/ViewDeclarePage.pm';
+
+tests(join ' ', qw(t/*.t t/*/*.t t/*/*/*.t t/*/*/*/*.t));
+
+WriteAll();
Added: jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage.pm Mon Dec 15 10:27:38 2008
@@ -0,0 +1,60 @@
+use 5.008;
+use utf8;
+use strict;
+use warnings;
+
+package Jifty::Plugin::ViewDeclarePage;
+use base qw/Jifty::Plugin/;
+
+our $VERSION = '0.01';
+
+=head1 NAME
+
+Jifty::Plugin::ViewDeclarePage - sexy replacement for suckish Jifty::View::Declare::Page
+
+=head1 DESCRIPTION
+
+All you need you'll find in L<Jifty::Plugin::ViewDeclarePage::Page> doc.
+
+Name sucks and I'm open for suggestions it's not late to rename.
+
+=head1 METHODS
+
+=head2 init
+
+Called during initialization. Tries to load YourApp::View::Page that
+is used by default as page implementation. If it's not there then
+simple is generated, otherwise checked if your page class is sub
+class of L<Jifty::Plugin::ViewDeclarePage::Page> and warning is issued
+if it's not.
+
+=cut
+
+sub init {
+ my $self = shift;
+ my $class = Jifty->app_class('View::Page');
+ if ( Jifty::Util->try_to_require($class) ) {
+ Jifty->log->warn(
+ "Plugin '". __PACKAGE__ ."' is used,"
+ ." but class '$class' is not subclass of '". __PACKAGE__ ."::Page'"
+ ) unless $class->isa( __PACKAGE__ .'::Page' );
+ } else {
+ my $page_class = __PACKAGE__ .'::Page';
+ eval "package $class; use strict; use warnings; use base '$page_class'; 1;"
+ or die $@;
+ Jifty->log->debug("Generated simple '$class' class");
+ }
+ return 1;
+}
+
+=head1 LICENSE
+
+Under the same terms as perl itself.
+
+=head1 AUTHOR
+
+Ruslan Zakirov E<lt>Ruslan.Zakirov at gmail.comE<gt>
+
+=cut
+
+1;
Added: jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage/Page.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/ViewDeclarePage/lib/Jifty/Plugin/ViewDeclarePage/Page.pm Mon Dec 15 10:27:38 2008
@@ -0,0 +1,603 @@
+package Jifty::Plugin::ViewDeclarePage::Page;
+
+use strict;
+use warnings;
+use base qw/Class::Accessor::Fast/;
+use Jifty::View::Declare -base;
+
+=head1 NAME
+
+Jifty::View::Declare::Page::NewStyle - new style page wrapper to simplify customization and reuse.
+
+=head1 DESCRIPTION
+
+This library is a replacement for L<Jifty::View::Declare::Page>.
+That is in Jifty for a while and can not be replaced with something
+completly different because of backwards compatibility.
+
+When you declare a L<Jifty::View::Declare> template that is a page, for example:
+
+ template 'news' => page {
+ ...
+ };
+
+Page classes come into game. First of all App::View::Page is loaded
+(it's not true and there is a way to define class for particular page,
+but lets leave it alone as interface is not settled enough to be
+discussed). If the app class doesn't exist then default
+L<Jifty::View::Declare::Page> is used. Code block right after page
+token is used to render core of the page wrapped into some layout.
+Page classes implement such layouts.
+
+It's very hard to extended L<Jifty::View::Declare::Page> class as
+it's written in such a way that forces you to copy&paste some
+internals from the class to make overriden method work and don't
+breake things.
+
+I think this implementation is much better thing. To use this class
+as a base for all your pages you can just add this plugin to your app
+and simple YourApp::View::Page will be generated for you. However,
+if you're here then you want to change layout, your App::View::Page
+should be something like:
+
+ package MyApp::View::Page;
+ use base qw(Jifty::Plugin::ViewDeclarePage::Page);
+ use Jifty::View::Declare::Helpers;
+
+ ...
+
+ 1;
+
+=head1 DIFFERENCES FROM DEFAULT PAGE CLASS
+
+=over 4
+
+=item no calls into templates
+
+Yes, that's it. No call to show('/menu'), instead it's a method
+L</render_navigation> here. Why? If it's subclassable then there is no
+need to split functionality between different modules. You
+can always return old behavior by using:
+
+ sub render_navigation { show(/menu) }
+
+=item no render_pre_content_hook
+
+override L</render_content>.
+
+=item title is always rendered in page
+
+Even when there is no 'title is ...' in the content code,
+see L</instrument_content> and L</render_title_inpage>.
+
+=item no html in title
+
+All HTML is just escaped. 99% of apps don't want to put tags inside
+title. Sure, it's wrapped into <h1> tag. See L</render_title_inpage>
+
+=item new 'add rel ...' and 'add rev ...'
+
+Can be used in the content code to define feeds, relative links and other
+cool stuff. See L</instrument_content> and L</render_link_inpage>.
+
+=item at last
+
+It's documented!
+
+=back
+
+=cut
+
+
+__PACKAGE__->mk_accessors(qw(content_code _title _links _meta));
+use constant allow_single_page => 1;
+
+=head1 ACCESSORS
+
+=over 4
+
+=item content_code
+
+Code reference that renders the core of the page, this is code block
+right after page token in the following example:
+
+ template 'news' => page {
+ ...
+ };
+
+Is set by jifty during construction of the page object.
+
+=item _meta
+
+A hash reference that is set by jifty during construction of
+the page object. It's empty unless you use the following syntax:
+
+ template my_page => page { some => 'value', ... } content {
+ ...
+ };
+
+In this case _meta is a reference to the hash that goes right after
+page token and content_code is after content token.
+
+=item _title and _links
+
+These are internal temporary holders of corresponding data.
+
+=back
+
+=head1 METHODS
+
+=head2 Initialization and rendering driver
+
+=head3 new
+
+Sets up a new page class. Called by Jifty with content_code and
+optional _meta.
+
+Calls L</init> right before returning new instance of the class.
+
+=cut
+
+sub new {
+ my $class = shift;
+ my $props = shift;
+ $props->{'_meta'} ||= {};
+ $props->{'_links'} ||= [];
+ my $self = $class->SUPER::new($props);
+ $self->init;
+ return $self;
+}
+
+=head3 init
+
+Sets _title accessor from 'title' in _meta if the latter is defined,
+so you can do the following if title of a page is static:
+
+ template news => page { title => _('News') } content {
+ ...
+ };
+
+=cut
+
+sub init {
+ my $self = shift;
+
+ if ( defined (my $title = $self->_meta->{'title'}) ) {
+ $self->_title( $title );
+ }
+
+ return $self;
+}
+
+=head3 render
+
+Renders whole page from doctype till closing html tag. Takes
+no arguments.
+
+This method drives rendering of the page. Page is splitted
+into three major parts: header, body and footer. Each is
+implemented as corresponding method with 'render_' prefix.
+
+It worth to note that order of rendering is changed and
+header is rendered after the body to allow you define page
+title, rss feeds and other thing in content. Read more
+about this below in L</render_header> and L</instrument_content>.
+
+=cut
+
+sub render {
+ my $self = shift;
+
+ Template::Declare->new_buffer_frame;
+ $self->render_body;
+ my $body = Template::Declare->end_buffer_frame->data;
+
+ $self->render_header;
+
+ Template::Declare->buffer->append( $body );
+
+ $self->render_footer;
+}
+
+=head2 Main blocks of the page
+
+=head3 render_header
+
+Renders an HTML "doctype" and complete <head> tag. Usually you don't
+want to override this. This method is rendered after body and main
+content of the page, so all things you need in head tag you can define
+in content.
+
+=over 4
+
+=item doctype
+
+Calls L</render_doctype>.
+
+=item C<title is ...>
+
+You can define dynamic title using the following:
+
+ template some => page {
+ my $page_title = ...;
+ ...
+ title is $page_title;
+ ...
+ };
+
+Don't want to define dynamic title then as well you can use syntax
+described in L</init> above.
+
+When 'title is' is used in the content code, L</render_title_inpage>
+is called, read more in L</instrument_content>.
+
+L</render_title_inhead> is called during rendering of the head tag,
+so you can change title there as well by subclassing that method.
+
+=item tag <link>, C<add rel ...> and C<add rev ...>
+
+You can add <link> tags right from the content using the following syntax:
+
+ add rel "alternate",
+ type => "application/atom+xml",
+ title => _('Updated this week'),
+ href => '/feeds/atom/recent',
+ ;
+
+When these constructions are used, L</render_link_inpage> is called
+so you can add something right in the page content, for example
+RSS image with link to the feed. See also L</instrument_content>.
+
+L</render_links_inhead> is called during rendering of the head tag.
+
+=item css and js
+
+Links to CSS and JS files are rendered for you using
+L<Jifty::Web/include_css> and L<Jifty::Web/include_js> functions.
+
+Read docs around those methods and L<Jifty::Manual> on adding your
+own styles and scripts.
+
+=item meta
+
+Not implemented, but will be as soon as syntax will be defined.
+
+=back
+
+=cut
+
+sub render_header {
+ my $self = shift;
+
+ $self->render_doctype;
+
+ head {
+ Jifty->handler->apache->content_type('text/html; charset=utf-8');
+ with(
+ 'http-equiv' => "content-type",
+ content => "text/html; charset=utf-8"
+ ), meta {};
+ $self->render_title_inhead( $self->_title );
+ $self->render_links_inhead( @{ $self->_links || [] } );
+ Jifty->web->include_css;
+ Jifty->web->include_javascript;
+ };
+ return '';
+};
+
+=head3 render_body
+
+Renders body tag, declares that we're in body and calls L</render_page>
+that actually defines layout of the body. L</render_page> method is better
+target for subclassing instead of this.
+
+=cut
+
+sub render_body {
+ my $self = shift;
+ body {
+ Jifty->handler->stash->{'in_body'} = 1;
+ $self->render_page;
+ Jifty->handler->stash->{'in_body'} = 0;
+ };
+ return '';
+}
+
+=head3 render_footer
+
+Renders the page footer - </html> tag :)
+
+=cut
+
+sub render_footer {
+ my $self = shift;
+ outs_raw('</html>');
+ return '';
+}
+
+=head2 Body layout
+
+=head3 render_page
+
+Renders the skeleton of the page and then calls L</instrument_content>
+to prepare and finally render L</content_code> using L</render_content>.
+
+Default layout of the page is the following:
+
+ <div>
+ <div>
+ this->render_salutation
+ this->render_navigation
+ </div>
+ <div id="content"><div>
+ this->instrument_content
+ this->render_jifty_page_detritus
+ </div></div>
+ </div>
+
+=cut
+
+sub render_page {
+ my $self = shift;
+ div {
+ div {
+ $self->render_salutation;
+ $self->render_navigation;
+ }
+ div { attr { id is 'content' };
+ div {
+ $self->instrument_content;
+ $self->render_jifty_page_detritus;
+ }
+ }
+ };
+ return '';
+}
+
+=head3 instrument_content
+
+Something you don't want ever touch. However, does the following:
+
+=over 4
+
+=item setups local 'title is ...' handler which calls L</render_title_inpage>
+if 'title is' is used.
+
+=item if 'title is' is not used then calls L</render_title_inpage> after
+and put result into output stream before the content.
+
+=item setup handler for 'add rel ...' and 'add rev ...', that calls
+L</render_link_inpage> and fills _links accessor.
+
+=item sure calls L</render_content>.
+
+=back
+
+=cut
+
+sub instrument_content {
+ my $self = shift;
+
+ no warnings qw( redefine once );
+
+ my $seen_title = 0;
+ local *is::title = sub {
+ shift;
+ $seen_title = 1;
+ no warnings qw(uninitialized);
+ my $res = '';
+ for (@_) {
+ if ( ref($_) eq 'CODE' ) {
+ Template::Declare->new_buffer_frame;
+ $_->();
+ $res .= Template::Declare->end_buffer_frame->data;
+ } else {
+ $res .= Jifty->web->escape($_);
+ }
+ }
+ $self->_title( $self->_title . $res );
+ $self->render_title_inpage( $self->_title );
+ return '';
+ };
+
+ local *rel::add = sub {
+ shift;
+ my %args = ('rel', @_);
+ my $links = $self->_links;
+ push @$links, \%args;
+ $self->_links( $links );
+ $self->render_link_inpage( %args );
+ return '';
+ };
+
+ local *rev::add = sub {
+ shift;
+ my %args = ('rev', @_);
+ my $links = $self->_links;
+ push @$links, \%args;
+ $self->_links( $links );
+ $self->render_link_inpage( %args );
+ return '';
+ };
+
+ Template::Declare->new_buffer_frame;
+ $self->render_content;
+ my $content = Template::Declare->end_buffer_frame->data;
+
+ unless ( $seen_title ) {
+ $self->render_title_inpage;
+ }
+
+ Template::Declare->buffer->append( $content );
+ return '';
+}
+
+=head3 render_content
+
+Renders content of the page - L</content_code>.
+
+=cut
+
+sub render_content {
+ my $self = shift;
+
+ $self->content_code->();
+
+ return '';
+}
+
+=head2 Helpers
+
+=head3 render_doctype
+
+Renders default doctype - XHTML 1.0 Strict.
+
+=cut
+
+sub render_doctype {
+ outs_raw(
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
+ .' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'. "\n"
+ .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'. "\n"
+ );
+ return '';
+}
+
+=head3 render_title_inhead
+
+Should output nothing but a title tag what will be placed into the head.
+Title is passed as onyl argument. Arguments are combined.
+
+=cut
+
+sub render_title_inhead {
+ my $self = shift;
+ my $title = shift
+ || Jifty->config->framework('ApplicationName');
+
+ title { $title };
+ return '';
+}
+
+=head3 render_title_inpage
+
+Renders the in-page title, followed by L<page navigation|Jifty::Web/page_navigation>
+and L<jifty messages|Jifty::Web/render_messages>.
+
+See L</render_title_inhead>, L</instrument_content> and L</render_header>.
+
+=cut
+
+sub render_title_inpage {
+ my $self = shift;
+ my $title = shift;
+
+ if ( $title ) {
+ h1 { attr { class => 'title' }; outs($title) };
+ }
+
+ Jifty->web->page_navigation->render_as_menu;
+
+ Jifty->web->render_messages;
+
+ return '';
+}
+
+=head3 render_links_inhead
+
+Renders link tags which are passed as list of hashes.
+
+=cut
+
+sub render_links_inhead {
+ my $self = shift;
+ my @links = @_;
+ foreach ( @links ) {
+ with ( %$_ ), link { };
+ }
+ return '';
+}
+
+=head3 render_link_inpage
+
+Do nothing by default, but link as a hash is passed
+when content has 'add rel ...' or 'add rev ...'.
+
+Read more in L</render_header> and L</instrument_content>.
+
+=cut
+
+sub render_link_inpage { return '' }
+
+=head3 render_navigation
+
+Renders L<Jifty::Web/navigation> as L<menu|Jifty::Web::Menu/render_as_menu>
+wrapped into a div with id 'navigation'. There is as well page_navigation
+in Jifty that is rendered in L</render_title_inpage> by default.
+
+Called from L</render_page>.
+
+=cut
+
+sub render_navigation {
+ div { attr { id => "navigation" };
+ Jifty->web->navigation->render_as_menu;
+ };
+ return '';
+}
+
+=head3 render_salutation
+
+Renders salutation for the current user wrapped into div with id equal to 'salutation'.
+Called from L</render_page>.
+
+=cut
+
+sub render_salutation {
+ my $cu = Jifty->web->current_user;
+ div { attr {id => "salutation" };
+ if ( $cu->id and $cu->user_object ) {
+ _( 'Hiya, %1.', $cu->username );
+ }
+ else {
+ _("You're not currently signed in.");
+ }
+ };
+ return '';
+}
+
+=head3 render_jifty_page_detritus
+
+Renders admin mode warning, the wait message, the keybindings and PubSub javascript.
+Called from L</render_page>.
+
+=cut
+
+sub render_jifty_page_detritus {
+ if ( Jifty->config->framework('AdminMode') ) {
+ with( class => "warning admin_mode" ), div {
+ outs( _('Alert') . ': ' );
+ outs_raw(
+ Jifty->web->tangent(
+ label => _('Administration mode is enabled.'),
+ url => '/__jifty/admin/'
+ )
+ );
+ }
+ }
+
+ with( id => "jifty-wait-message", style => "display: none" ),
+ div { _('Loading...') };
+
+ div { id is "keybindings";
+ script { outs_raw('Jifty.KeyBindings.reset()') }
+ };
+
+ # This is required for jifty server push
+ if ( Jifty->config->framework('PubSub')->{'Enable'} && Jifty::Subs->list )
+ {
+ script { outs_raw('new Jifty.Subs({}).start();') };
+ }
+}
+
+1;
More information about the Jifty-commit
mailing list