package CPAN::Mini::Webserver::Templates; use strict; use warnings; use Template::Declare::Tags; use base 'Template::Declare'; private template 'header' => sub { my ( $self, $title ) = @_; head { title {$title}; link { attr { rel => 'stylesheet', href => '/static/css/screen.css', type => 'text/css', media => 'screen, projection' } }; link { attr { rel => 'stylesheet', href => '/static/css/print.css', type => 'text/css', media => 'print' } }; outs_raw ''; link { attr { rel => 'icon', href => '/static/images/favicon.png', type => 'image/png', } }; link { attr { rel => 'search', href => '/static/xml/opensearch.xml', type => 'application/opensearchdescription+xml', title => 'minicpan search', } }; meta { attr { generator => 'CPAN::Mini::Webserver' } }; } }; private template 'footer' => sub { my $self = shift; my $version = $CPAN::Mini::Webserver::VERSION; div { attr { id => "footer" }; small { "Generated by CPAN::Mini::Webserver $version"; }; } }; private template 'author_link' => sub { my ( $self, $author ) = @_; a { attr { href => '/~' . lc( $author->pauseid ) . '/' }; $author->name; }; }; private template 'distribution_link' => sub { my ( $self, $distribution ) = @_; a { attr { href => '/~' . lc( $distribution->cpanid ) . '/' . $distribution->distvname . '/' }; $distribution->distvname; }; }; private template 'package_link' => sub { my ( $self, $package ) = @_; my $distribution = $package->distribution; a { attr { href => '/package/' . lc( $distribution->cpanid ) . '/' . $distribution->distvname . '/' . $package->package . '/' }; $package->package; }; }; private template distribution_file => sub { my ( $self, $pauseid, $distvname, $filename ) = (@_); my $display_filename = ( $filename =~ /^$distvname\/(.*)$/ ) ? $1 : $filename; my $href = ( $filename =~ /\.(pm|pod)$/ ) ? "/~$pauseid/$distvname/$filename" : "/raw/~$pauseid/$distvname/$filename"; row { cell { a { attr { href => $href }; span { $display_filename; }; }; }; }; }; private template 'searchbar' => sub { my $self = shift; my $q = shift; table { row { form { attr { name => 'f', method => 'get', action => '/search/' }; cell { attr { class => 'searchbar' }; outs_raw q||; }; cell { attr { class => 'searchbar' }; input { { attr { type => 'text', name => 'q', value => $q } }; }; input { { attr { type => 'submit', value => 'Search Mini CPAN' } }; }; }; }; }; }; }; private template 'search_results' => sub { my ( $self, $arguments ) = @_; my $parse_cpan_authors = $arguments->{parse_cpan_authors}; my $q = $arguments->{q}; my @authors = @{ $arguments->{authors} }; my @distributions = @{ $arguments->{distributions} }; my @packages = @{ $arguments->{packages} }; if ( @authors + @distributions + @packages ) { outs_raw ''; foreach my $author (@authors) { row { cell { show( 'author_link', $author ); }; }; } foreach my $distribution (@distributions) { row { cell { show( 'distribution_link', $distribution ); outs ' by '; show( 'author_link', $parse_cpan_authors->author( $distribution->cpanid ) ); }; }; } foreach my $package (@packages) { row { cell { show( 'package_link', $package ); outs ' by '; show( 'author_link', $parse_cpan_authors->author( $package->distribution->cpanid ) ); }; }; } outs_raw '
'; } else { p {'No results found.'}; } }; template 'index' => sub { my ( $self, $arguments ) = @_; my $parse_cpan_authors = $arguments->{parse_cpan_authors}; my $recents = $arguments->{recents}; html { attr { xmlns => 'http://www.w3.org/1999/xhtml' }; div { attr { class => 'container' }; div { attr { class => 'span-24' }; show( 'header', 'Index' ); body { attr { onload => 'document.f.q.focus()' }; show('searchbar'); h1 {'Index'}; p {'Welcome to CPAN::Mini::Webserver. Start searching!'}; if ($recents) { h2 {'Recent distributions'}; ul { foreach my $recent (@$recents) { my $cpanid = $recent->cpanid; my $distvname = $recent->distvname; next unless $distvname; li { a { attr { href => '/~' . lc($cpanid) . '/' . $distvname }; $distvname; }; outs ' by '; show( 'author_link', $parse_cpan_authors->author( $cpanid ) ); } } }; } }; show('footer'); }; }; }; }; template '404' => sub { my ( $self, $arguments ) = @_; my $q = $arguments->{q}; html { attr { xmlns => 'http://www.w3.org/1999/xhtml' }; div { attr { class => 'container' }; div { attr { class => 'span-24' }; show( 'header', 'File not found' ); body { show( 'searchbar', $q ); h1 {'Sorry. I couldn\'t find the page you wanted.'}; p { "Unfortunately, the page you were looking for doesn't exist. Perhaps a quick search for $q will turn up what you were looking for:"; }; }; h2 { outs "Search for "; outs_raw '“'; outs $q; outs_raw '”'; }; show( 'search_results', $arguments ); show('footer'); }; }; }; }; template 'search' => sub { my ( $self, $arguments ) = @_; my $q = $arguments->{q}; html { show( 'header', "Search for `$q'" ); body { div { attr { class => 'container' }; div { attr { class => 'span-24' }; show( 'searchbar', $q ); h1 { outs "Search for "; outs_raw '“'; outs $q; outs_raw '”'; }; show( 'search_results', $arguments ); show('footer'); } }; } }; }; private template 'authorinfo' => sub { my ( $self, $author ) = @_; my $pauseid = $author->pauseid; my $email = $author->email; my $url = $author->can('homepage') ? $author->homepage : undef; my $prefix = 'id' . '/' . substr( $pauseid, 0, 1 ) . '/' . substr( $pauseid, 0, 2 ) . '/' . $pauseid; h2 {"Links"}; ul { li { a { attr { href => "http://backpan.perl.org/authors/$prefix" }; 'BackPAN'; }; } li { a { attr { href => "mailto:$email" }; $email; }; } li { a { attr { href => $url }; $url; }; } li { a { attr { href => "http://cpantesters.perl.org/author/$pauseid.html" }; 'CPANTesters'; }; } li { a { attr { href => "http://bbbike.radzeit.de/~slaven/cpantestersmatrix.cgi?author=$pauseid" }; 'Test Matrix'; }; } } }; template 'author' => sub { my ( $self, $arguments ) = @_; my $author = $arguments->{author}; my $pauseid = $arguments->{pauseid}; my $distvname = $arguments->{distvname}; my @distributions = @{ $arguments->{distributions} }; my $dates = $arguments->{dates}; html { show( 'header', $author->name ); body { div { attr { class => 'container' }; div { attr { class => 'span-24 last' }; show('searchbar'); h1 { show( 'author_link', $author ) }; } div { attr { class => 'span-18 last' }; outs_raw ''; foreach my $distribution (@distributions) { row { cell { show( 'distribution_link', $distribution ); }; cell { outs $dates->{ $distribution->distvname }; }; }; } outs_raw '
'; } div { attr { class => 'span-6 last' }; show( 'authorinfo', $author ); }; div { attr { class => 'span-24 last' }; show('footer'); }; }; }; } }; private template 'dependencies' => sub { my ( $self, $meta, $pcp ) = @_; div { attr { class => 'dependencies' }; h2 {'Dependencies'}; ul { foreach my $deptype (qw(requires build_requires configure_requires)) { if ( defined $meta->{$deptype} ) { foreach my $package ( sort keys %{ $meta->{$deptype} } ) { next if $package eq 'perl'; my $d = $pcp->package($package)->distribution; next unless $d; my $distvname = $d->distvname; my $author = $d->cpanid; li { a { attr { href => "/~$author/$distvname/" }; $package; }; if ( $deptype =~ /(.*?)_/ ) { outs " ($1 requirement)"; } } } } } } } }; private template 'metadata' => sub { my ( $self, $meta ) = @_; h2 {'Metadata'}; div { attr { class => 'metadata' }; dl { foreach my $key ( qw(abstract license repository), 'release date' ) { if ( defined $meta->{$key} ) { dt { ucfirst $key; }; if ( defined $meta->{resources}->{$key} ) { a { attr { href => delete $meta->{resources}->{$key} }; $meta->{$key}; }; } else { dd { $meta->{$key} }; } } } foreach my $datum ( keys %{ $meta->{resources} } ) { dt { ucfirst $datum; } dd { a { attr { href => $meta->{resources}->{$datum}; }; $meta->{resources}->{$datum}; } } } } }; }; private template 'download' => sub { my ( $self, $author, $distribution ) = @_; my $distvname = $distribution->distvname; h2 {'Download'}; div { a { attr { href => '/download/~' . $author->pauseid . "/$distvname" }; $distribution->filename; } }; }; private template 'install' => sub { my ( $self, $author, $distribution, $filenames ) = @_; my $distvname = $distribution->distvname; # Check whether we have the module/distribution installed # And display the status # Just fudge: # * If we have lib/*.pm, that's a contained module my @modules = map { m![^/]*/lib/(.*?)\.pm!; $_ = $1; s!/!::!g; $_ } grep { m![^/]*/lib/.*?\.pm$! } @{$filenames}; my $installed_version = Module::InstalledVersion->new( $modules[0] ); my $msg = "Not installed on this Perl"; my $action = 'Install'; if ( $installed_version->{version} ) { $msg = sprintf 'You have version %s installed.', $installed_version->{version}; if ( $installed_version->{version} lt $distribution->version ) { $action = 'Update'; } elsif ( $installed_version->{version} eq $distribution->version ) { $action = 'Reinstall'; } else { $action = 'Downgrade'; } } h2 {'Install'}; div { attr { class => 'install' }; div { attr { 'class' => "install-message" }; $msg }; form { attr { class => 'install-link' } attr { method => 'PUT' }; attr { action => '/install/~' . lc( $distribution->cpanid ) . '/' . $distribution->distvname . '/' . $distribution->filename; }; button {$action} $action; }; }; }; private template 'dist_links' => sub { my ( $self, $distribution ) = @_; my $distname = $distribution->dist; h2 {'Links'}; ul { li { outs "Test "; a { attr { href => "http://bbbike.radzeit.de/~slaven/cpantestersmatrix.cgi?dist=$distname" }; "matrix"; }; outs " and "; a { attr { href => "http://cpantesters.perl.org/show/$distname.html" }; "reports"; }; } li { a { attr { href => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=$distname" }; "RT"; }; outs " (or via "; a { attr { href => "mailto:bug-$distname\@rt.cpan.org" } "email"; }; outs ")"; } li { a { attr { href => "http://annocpan.org/dist/$distname" }; "AnnoCPAN"; } } li { a { attr { href => "http://cpanratings.perl.org/d/$distname" }; "CPAN Ratings"; } } } }; template 'filelist' => sub { my ( $self, $pauseid, $distvname, $label, $filenames ) = @_; h2 {$label}; outs_raw ''; foreach my $filename (@$filenames) { show( distribution_file => $pauseid, $distvname, $filename ); } outs_raw '
'; }; template 'distribution' => sub { my ( $self, $arguments ) = @_; my $author = $arguments->{author}; my $pauseid = $arguments->{pauseid}; my $distvname = $arguments->{distvname}; my $distribution = $arguments->{distribution}; my @filenames = @{ $arguments->{filenames} }; my $meta = $arguments->{meta}; my $pcp = $arguments->{pcp}; html { show( 'header', $author->name . ' > ' . $distvname ); body { div { attr { class => 'container' }; div { attr { class => 'span-24 last' }; show('searchbar'); h1 { show( 'author_link', $author ); outs ' > '; show( 'distribution_link', $distribution ); }; } div { attr { class => 'span-18 last' }; # outs_raw ''; my ( @code, @test, @other, @doc ); foreach (@filenames) { if ( m{(?:/bin/|\.p(?:m|l)$)} and not m{/inc/} ) { push @code, $_; } elsif (m{\.pod$}) { push @doc, $_; } elsif (/\.t$/) { push @test, $_; } else { push @other, $_; } } show( 'filelist', $pauseid, $distvname, 'Code', \@code ) if @code; show( 'filelist', $pauseid, $distvname, 'Documentation', \@doc ) if @doc; show( 'filelist', $pauseid, $distvname, 'Tests', \@test ) if @test; show( 'filelist', $pauseid, $distvname, 'Other', \@other ) if @other; # foreach my $filename (@filenames) { # show( # distribution_file => $pauseid, # $distvname, $filename # ); # } # outs_raw '
'; }; div { attr { class => 'span-6 last' }; show( 'metadata', $meta ); show( 'dependencies', $meta, $pcp ); show( 'download', $author, $distribution ); show( 'install', $author, $distribution, \@filenames ); show( 'dist_links', $distribution ); }; div { attr { class => 'span-24 last' }; show('footer'); }; } }; } }; template 'file' => sub { my ( $self, $arguments ) = @_; my $author = $arguments->{author}; my $distribution = $arguments->{distribution}; my $filename = $arguments->{filename}; my $pauseid = $arguments->{pauseid}; my $distvname = $arguments->{distvname}; my $file = $arguments->{filename}; my $contents = $arguments->{contents}; my $html = $arguments->{html}; html { show( 'header', $author->name . ' > ' . $distvname . ' > ' . $filename ); body { div { attr { class => 'container' }; div { attr { class => 'span-24' }; show('searchbar'); h1 { show( 'author_link', $author ); outs ' > '; show( 'distribution_link', $distribution ); outs ' > '; outs $filename; }; a { attr { href => "/raw/~$pauseid/$distvname/$filename" }; "See raw file"; }; if ($html) { div { attr { id => "pod" }; outs_raw $html; }; } else { pre {$contents}; } show('footer'); }; }; }; } }; template 'raw' => sub { my ( $self, $arguments ) = @_; my $author = $arguments->{author}; my $distribution = $arguments->{distribution}; my $filename = $arguments->{filename}; my $pauseid = $arguments->{pauseid}; my $distvname = $arguments->{distvname}; my $contents = $arguments->{contents}; my $html = $arguments->{html}; html { show( 'header', $author->name . ' > ' . $distvname . ' > ' . $filename ); body { div { attr { class => 'container' }; div { attr { class => 'span-24' }; show('searchbar'); h1 { show( 'author_link', $author ); outs ' > '; show( 'distribution_link', $distribution ); outs ' > '; outs $filename; }; if ($html) { div { attr { id => "code" }; code { outs_raw $html; }; }; } else { pre {$contents}; } div { attr { class => 'download-link' }; a { attr { href => '/download/~' . $author->pauseid . "/$distvname/$filename" }; "Download as plain text"; }; }; show('footer'); }; }; }; } }; template 'opensearch' => sub { my $self = shift; outs_raw q| minicpan_webserver Search minicpan UTF-8 data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%08%03%00%00%00(-%0FS%00%00%00%01sRGB%00%AE%CE%1C%E9%00%00%003PLTE8%00%00%05%08%04%16%18%15%1E%1F%1D!%22%20%26(%26%2C-%2B130%3B%3D%3AFHELMKXZWegdxyw%84%86%83%9E%A0%9D%CC%CE%CBjq%F6r%00%00%00%01tRNS%00%40%E6%D8f%00%00%00lIDAT%18%D3u%8FY%0E%C20%0C%05%BD%AF)%ED%FDO%0B%85%10%15%04%EF%C7%1A%7B%2C%D9%00%7Fr%C4W%A3u%EB%2B%EFn%E3sAnr1%8E%E11%D4rq%1Bn%9E%CC%8B%15%C5%01%14u%B2%A0%3EmA9K1Z%BD%5C%C6%87%18%B4%18%8A0%A0Q%2B%C3%CC%232%9D%CE%19%E1%3B%3C%E6%E6%CA%BC%C4%A5%BB%C2%84%FC%D7%DBw%7BS%02%E3Ki%23G%00%00%00%00IEND%AEB%60%82 |; }; __END__ =head1 NAME CPAN::Mini::Webserver::Templates - Templates for CPAN::Mini::Webserver =head1 DESCRIPTION This module holds the templates, CSS and images for CPAN::Mini::Webserver. =head1 AUTHOR Leon Brocard =head1 COPYRIGHT Copyright (C) 2008, Leon Brocard. This module is free software; you can redistribute it or modify it under the same terms as Perl itself.