container widget
matthewt [Tue, 29 Jan 2008 11:35:18 +0000 (11:35 +0000)]
lib/ComponentUI/View/Site/Widget/Layout.pm [deleted file]
lib/Reaction/UI/LayoutSet.pm
lib/Reaction/UI/Widget.pm
lib/Reaction/UI/Widget/Container.pm [new file with mode: 0644]
share/skin/default/layout/layout.tt

diff --git a/lib/ComponentUI/View/Site/Widget/Layout.pm b/lib/ComponentUI/View/Site/Widget/Layout.pm
deleted file mode 100644 (file)
index 5fef458..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package ComponentUI::View::Site::Widget::Layout;
-
-use Reaction::UI::WidgetClass;
-
-class Layout, which {
-
-  implements fragment main_content {
-    if (my $inner = $_{viewport}->inner) {
-      arg '_' => $inner;
-      render 'viewport';
-    }
-  };
-
-};
-
-1;
index b3793af..de00c7c 100644 (file)
@@ -10,12 +10,15 @@ class LayoutSet which {
   has 'name' => (is => 'ro', required => 1);
 
   has 'source_file' => (is => 'rw', lazy_fail => 1);
+
   has 'file_extension'=> (isa => 'Str', is => 'rw', lazy_build => 1);
 
   has 'widget_class' => (
     is => 'rw', lazy_fail => 1, predicate => 'has_widget_class'
   );
 
+  has 'widget_type' => (is => 'rw', lazy_build => 1);
+
   has 'super' => (is => 'rw', predicate => 'has_super');
 
   implements _build_file_extension => as { 'html' };
@@ -86,6 +89,9 @@ class LayoutSet which {
       } elsif ($data =~ /^extends (\S+)/) {
         my $super_name = $1;
         $self->super($build_args->{view}->create_layout_set($super_name))
+      } elsif ($data =~ /^widget (\S+)/) {
+        my $widget_type = $1;
+        $self->widget_type($1);
       } elsif ($data =~ /^cut/) {
         # no-op
       } else {
@@ -95,7 +101,7 @@ class LayoutSet which {
     $self->source_file($file);
   };
 
-  implements 'widget_type' => as {
+  implements '_build_widget_type' => as {
     my ($self) = @_;
     my $widget = join('',   map { ucfirst($_) } split('_', $self->name));
     $widget    = join('::', map { ucfirst($_) } split('/', $widget));
index 9d1e08e..2c7e00c 100644 (file)
@@ -34,13 +34,18 @@ class Widget which {
     $rctx->dispatch($render_tree, $new_args);
   };
 
+  implements '_method_for_fragment_name' => as {
+    my ($self, $fragment_name) = @_;
+    return $self->can("_fragment_${fragment_name}");
+  };
+
   implements '_render_dispatch_order' => as {
     my ($self, $fragment_name, $args, $new_args) = @_;
 
     my @render_stack = (my $render_deep = (my $render_curr = []));
     my @layout_order = $self->layout_set->widget_order_for($fragment_name);
 
-    if (my $f_meth = $self->can("_fragment_${fragment_name}")) {
+    if (my $f_meth = $self->_method_for_fragment_name($fragment_name)) {
       my @wclass_stack;
       my $do_render = sub {
         my $package = shift;
diff --git a/lib/Reaction/UI/Widget/Container.pm b/lib/Reaction/UI/Widget/Container.pm
new file mode 100644 (file)
index 0000000..3b11afb
--- /dev/null
@@ -0,0 +1,59 @@
+package Reaction::UI::Widget::Container;
+
+use Reaction::UI::WidgetClass;
+
+use aliased 'Reaction::UI::ViewPort';
+
+class Container which {
+
+  our $child_name;
+
+  # somewhat evil. fragment returns ($name, $code) to pass to implements
+  # or a method modifier name, so [1] will get us just the code
+
+  # This is convenient to do here but DO NOT duplicate this code outside of
+  # the same dist as WidgetClass since it's internals-dependent.
+
+  my $child_fragment_method
+    = (fragment container_child {
+         arg '_' => $_{viewport}->$child_name;
+         render 'viewport';
+       })[1];
+
+  around _method_for_fragment_name => sub {
+    my $orig = shift;
+    my $self = shift;
+    my ($fragment_name) = @_;
+    if (defined($child_name)
+        && $fragment_name eq $child_name) {
+      return $self->$orig(@_) || $child_fragment_method;
+    }
+    return $self->$orig(@_);
+  };
+    
+  before _fragment_widget => sub {
+    my ($self, $do_render, $args, $new_args) = @_;
+    my @contained_names = $self->_contained_names($args->{viewport});
+    foreach my $name (@contained_names) {
+      $new_args->{$name} ||= sub {
+        local $child_name = $name;
+        $self->render($name, @_);
+      };
+    }
+  };
+
+  implements _contained_names => sub {
+    my ($self, $vp) = @_;
+    my @names;
+    foreach my $attr ($vp->meta->compute_all_applicable_attributes) {
+      next unless eval { $attr->type_constraint->name->isa(ViewPort) };
+      my $name = $attr->name;
+      next if ($name eq 'outer');
+      push(@names, $name);
+    }
+    return @names;
+  };
+
+};
+
+1;
index 95cc025..15b535b 100644 (file)
@@ -1,3 +1,5 @@
+=widget Container
+
 =for layout widget
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
@@ -25,7 +27,7 @@
     <div id="contents">
       <div id="wrapper">
         [% sidebar %]
-        [% main_content %]
+        [% inner %]
       </div>
       <div class="spacer"></div>
     </div>
@@ -34,7 +36,7 @@
 
 </html>
 
-=for layout main_content
+=for layout inner
 <!-- main content start -->
 [% call_next %]
 <!-- main content end -->