sidebar filter
Matt S Trout [Wed, 9 Feb 2011 05:23:24 +0000 (05:23 +0000)]
lib/SCSite.pm
lib/SCSite/Filter.pm
lib/SCSite/LatestPageSet.pm
lib/SCSite/Page.pm
lib/SCSite/PageSet.pm
lib/SCSite/SidebarFilter.pm [new file with mode: 0644]
share/skin/layout.html
t/pages.t

index ffa9cb2..7d821d4 100644 (file)
@@ -25,7 +25,11 @@ sub _build_pages {
 sub _build_filters {
   my ($self) = @_;
   require SCSite::SubListFilter;
-  +{ SubList => SCSite::SubListFilter->new }
+  require SCSite::SidebarFilter;
+  +{
+    map +($_ => "SCSite::${_}Filter"->new_from_site($self)),
+      qw(SubList Sidebar)
+  }
 }
 
 sub dispatch_request {
@@ -70,13 +74,19 @@ sub _page_http_response {
 sub _render_page {
   my ($self, $page) = @_;
   my $zoom = $self->_layout_zoom;
-  $zoom->select('.title')->replace_content($page->title)
+  my %filters = %{$self->filters};
+  $zoom->select('.page.title')->replace_content($page->title)
        ->select('meta[name=description]')->replace_content($page->description)
        ->select('meta[name=keywords]')->replace_content($page->keywords)
        ->select('.main')->replace_content(\$page->body)
-       ->select('.SubList')->collect({
-           filter => $self->filters->{SubList}->callback_for($page),
-           passthrough => 1,
+       ->apply(sub {
+           foreach my $fname (sort keys %filters) {
+             my $cb = $filters{$fname}->callback_for($page);
+             $_ = $_->select(".${fname}")->collect({
+                        filter => $cb, passthrough => 1
+                      });
+           }
+           $_
          })
        ->to_fh
 }
index bbf442a..6897fc7 100644 (file)
@@ -4,6 +4,8 @@ use Moo::Role;
 
 requires '_filter_stream';
 
+sub new_from_site { shift->new }
+
 sub callback_for {
   my ($self, @args) = @_;
   sub {
index 327fb2c..dbeca56 100644 (file)
@@ -8,9 +8,10 @@ has _max_entries => (is => 'ro', required => 1, init_arg => 'max_entries');
 sub flatten {
   my ($self) = @_;
   my @sorted = sort {
-    $a->created cmp $b->created
+    $b->created cmp $a->created
   } $self->_parent->flatten;
-  $self->_max_entries ? @sorted[0..$self->_max_entries-1] : @sorted;
+  my $max = $self->_max_entries||0;
+  @sorted > $max ? @sorted[0..$max-1] : @sorted;
 }
 
 sub map {
index a0e5c15..cba4d6a 100644 (file)
@@ -8,12 +8,17 @@ has $_ => (is => 'ro') for qw(title description keywords body created path);
 has "_$_" => (is => 'ro', init_arg => $_) for qw(page_set);
 
 sub children {
-  my ($self) = @_;
+  my ($self, %args) = @_;
+  if (my $at = delete $args{at_depth}) {
+warn "Here, $at";
+    @args{qw(min_depth max_depth)} = ($at-1, $at);
+  }
   my $ps = $self->_page_set;
   (ref $ps)->new(
     top_dir => $ps->base_dir,
     base_dir => io->dir($ps->base_dir)->catdir($self->path),
-    max_depth => 1
+    max_depth => 1,
+    %args,
   );
 }
 
index 3f7d307..a1e12f5 100644 (file)
@@ -11,6 +11,7 @@ use Moo;
 has top_dir => (is => 'ro', lazy => 1, builder => 'base_dir');
 has base_dir => (is => 'ro', required => 1);
 has max_depth => (is => 'ro', default => quote_sub q{ 0 });
+has min_depth => (is => 'ro', default => quote_sub q{ 0 });
 
 has rel_path => (is => 'lazy');
 
@@ -31,7 +32,7 @@ sub get {
   }}->filter(sub {
         $_->filename =~ /^\Q${file}\E${\$self->_types_re}$/ and $type = $1
       })
-    ->all_files;
+    ->${\sub { $_[0]->exists ? $_[0]->all_files : () }};
   die "multiple files found for ${\$spec->{path}}:\n".join "\n", @poss
     if @poss > 1;
   return undef unless @poss;
@@ -45,18 +46,35 @@ sub map {
   [ map $mapper->($_), $self->flatten ]
 }
 
+sub _depth_under_base {
+  my ($self, $path) = @_;
+  File::Spec->splitdir(File::Spec->abs2rel($path, $self->base_dir->name))
+}
+
 sub flatten {
   my ($self) = @_;
+  return unless (my $base = $self->base_dir)->exists;
   my %seen;
   my $slash = io->dir('/');
+  my $min = $self->min_depth;
+  my @dirs = map $min ? $_->all_dirs($min) : $_, $base;
   map {
     my ($path, $type) = $_->name =~ /^(.*)${\$self->_types_re}$/;
     $self->${\"_inflate_${type}"}(
-      $slash->catdir(File::Spec->abs2rel($path, $self->top_dir->name)), $_->all
+      $slash->catdir(File::Spec->abs2rel($path, $self->top_dir->name)),
+      $_->all
     );
-  } io->dir($self->base_dir)
-      ->filter(sub { $_->filename =~ /${\$self->_types_re}$/ })
-      ->all_files($self->max_depth)
+  } map {
+    $_->filter(sub { $_->filename =~ /${\$self->_types_re}$/ })
+      ->all_files($self->max_depth - $min)
+  } map
+      $min
+        ? do {
+            # can't use ->all_dirs($min) since we only want the final level
+            my @x = ($_); @x = map $_->all_dirs, @x for 1..$min; @x
+          }
+        : $_,
+      $self->base_dir;
 }
 
 sub latest {
diff --git a/lib/SCSite/SidebarFilter.pm b/lib/SCSite/SidebarFilter.pm
new file mode 100644 (file)
index 0000000..d5c28ad
--- /dev/null
@@ -0,0 +1,75 @@
+package SCSite::SidebarFilter;
+
+use Moo;
+
+with 'SCSite::Filter';
+
+has _page_set => (is => 'ro', required => 1);
+
+sub new_from_site {
+  my ($class, $site) = @_;
+  $class->new(_page_set => $site->pages);
+}
+
+sub _latest_news {
+  shift->_page_set
+       ->get({ path => '/news/archive' })
+       ->children(at_depth => 3)
+       ->latest(2)
+       ->flatten;
+}
+
+sub _latest_news_archives {
+  shift->_page_set
+       ->get({ path => '/news/archive' })
+       ->${\sub { # archive page plus three latest per-month
+           my $o = shift;
+           ($o, $o->children(at_depth => 2)->latest(3)->flatten)
+         }};
+}
+
+sub _latest_blog_posts {
+  shift->_page_set
+       ->get({ path => '/blog' })
+       ->children(min_depth => 2, max_depth => 0)
+       ->latest(4)
+       ->flatten;
+}
+
+sub _sidebar_structure {
+  my ($self) = @_;
+  [
+    [ 'NEWS',
+      [ 'Latest News Items', $self->_latest_news ],
+      [ 'Archives', $self->_latest_news_archives ],
+    ],
+    [ 'BLOGS',
+      [ 'Latest Blog Posts', $self->_latest_blog_posts ],
+    ],
+  ];
+}
+
+sub _filter_stream {
+  my ($self, $stream) = @_;
+  my @blocks = @{$self->_sidebar_structure};
+  $stream->select('.sidebar.block')->repeat([
+             map { my ($t, @seg) = @$_; sub {
+               $_->select('.sidebar.title')->replace_content($t)
+                 ->select('.sidebar.segment')->repeat([
+                     map { my ($s, @e) = @$_; warn $s; warn @e; sub {
+                       $_->select('.sidebar.subtitle')->replace_content($s)
+                         ->select('.sidebar.entries')->repeat_content([
+                             map { my $e = $_; sub {
+                               $_->select('.entry.title')
+                                 ->replace_content($e->title)
+                                 ->select('.entry.link')
+                                 ->set_attribute(href => $e->path)
+                             } } @e
+                           ])
+                     } } @seg
+                   ])
+             } } @blocks
+           ])
+}
+
+1;
index e459fb3..cf54d8b 100644 (file)
@@ -1,11 +1,11 @@
 <html>
   <head>
-    <title class="title">page title</title>
+    <title class="page title">page title</title>
     <meta name="description" />
     <meta name="keywords" />
   </head>
   <body>
-    <div class="title">page title</div>
+    <div class="page title">page title</div>
     <div>
       <ul class="topbar_entries">
         <li><a href="/">Home</a></li>
       </ul>
     <div>
     <div class="Sidebar">
-      <div class="sidebar_segment">
-        <h4 class="sidebar_title"></h4>
-        <ul class="sidebar_entries">
-          <li><a class="entry"></a></li>
-        </ul>
+      <div class="sidebar block">
+        <h4 class="sidebar title"></h4>
+        <div class="sidebar segment">
+          <h5 class="sidebar subtitle"></h5>
+          <ul class="sidebar entries">
+            <li><a class="entry title link"></a></li>
+          </ul>
+        </div>
       </div>
     </div>
     <div class="main" />
index 3c51571..693e14d 100644 (file)
--- a/t/pages.t
+++ b/t/pages.t
@@ -1,6 +1,7 @@
 use strictures 1;
 use Test::More;
 use SCSite::PageSet;
+use IO::All;
 
 sub check_structure {
   my ($s) = @_;
@@ -8,6 +9,7 @@ sub check_structure {
   my $body = delete $s->{body};
   like($body, qr/^\s+<p>Some markdown here.<\/p>\s+$/sm, 'Body correct');
   delete @{$s}{grep /^_/, keys %$s};
+  delete $s->{path};
   is_deeply($s,
     {
       created => '',
@@ -19,7 +21,7 @@ sub check_structure {
   );
 }
 
-my $ps = SCSite::PageSet->new(base_dir => 't/pages');
+my $ps = SCSite::PageSet->new(base_dir => io->dir('t/pages'));
 
 my $test_html = q{<html>
   <head>