allow use of the new template system from static pages
authorTony Cook <tony@develop-help.com>
Mon, 28 May 2012 05:40:08 +0000 (15:40 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 28 May 2012 05:40:08 +0000 (15:40 +1000)
.gitignore
site/cgi-bin/modules/Article.pm
site/cgi-bin/modules/BSE/Regen.pm
site/cgi-bin/modules/BSE/TB/SiteCommon.pm
site/cgi-bin/modules/BSE/TB/TagOwner.pm
site/cgi-bin/modules/BSE/Template.pm
site/cgi-bin/modules/Generate.pm
site/cgi-bin/modules/Generate/Article.pm
site/docs/makedocs
site/templates/base.tmpl
t/t20gen.t

index 8425a88b26cad08b2f0d3bfcc5af4d013c6619df..475496618bb7300bb5b6b976e8c9d8e91fdd43f2 100644 (file)
@@ -4,6 +4,9 @@ INSTALL.html
 INSTALL.txt
 site/cgi-bin/modules/BSE/Modules.pm
 site/cgi-bin/modules/BSE/Version.pm
+site/docs/Article.html
+site/docs/BSE::TB::SiteCommon.html
+site/docs/BSE::TB::TagOwner.html
 site/docs/BSE::UI::Affiliate.html
 site/docs/Generate.html
 site/docs/Generate::Article.html
index ce623223df8e82a9d07ce287e27ed415d6666cea..f011ad2cccdea19adfa5aa26ca63d8b13360a739 100644 (file)
@@ -8,7 +8,29 @@ use vars qw/@ISA/;
 @ISA = qw/Squirrel::Row BSE::TB::SiteCommon BSE::TB::TagOwner/;
 use Carp 'confess';
 
-our $VERSION = "1.011";
+our $VERSION = "1.012";
+
+=head1 NAME
+
+Article - article objects for BSE.
+
+=head1 SYNOPSIS
+
+  use BSE::API qw(bse_make_article);
+
+  my $article = bse_make_article(...)
+
+  my $article = Articles->getByPkey($id);
+
+=head1 DESCRIPTION
+
+Implements the base article object for BSE.
+
+=head1 USEFUL METHODS
+
+=over
+
+=cut
 
 sub columns {
   return qw/id parentid displayOrder title titleImage body
@@ -32,6 +54,12 @@ sub numeric {
      customInt1 customInt2 customInt3 customInt4 menu);
 }
 
+=item section
+
+Return the article's section.
+
+=cut
+
 sub section {
   my ($self) = @_;
 
@@ -44,6 +72,12 @@ sub section {
   return $section;
 }
 
+=item parent
+
+Return the article's parent.
+
+=cut
+
 sub parent {
   my ($self) = @_;
   $self->{parentid} == -1 and return;
@@ -74,6 +108,12 @@ sub update_dynamic {
   $self->{cached_dynamic} = $dynamic;
 }
 
+=item is_dynamic
+
+Return true if the article is rendered dynamically.
+
+=cut
+
 sub is_dynamic {
   $_[0]{cached_dynamic};
 }
@@ -307,6 +347,12 @@ sub link {
   return $link;
 }
 
+=item admin
+
+Return the admin link for the article.
+
+=cut
+
 sub admin {
   my ($self) = @_;
 
@@ -354,6 +400,57 @@ sub is_released {
   return $self->release le _expire_release_datetime();
 }
 
+=item listed_in_menu
+
+Return true if the article should be listed in menus.
+
+=cut
+
+sub listed_in_menu {
+  my $self = shift;
+
+  return $self->listed == 1;
+}
+
+=item ancestors
+
+Returns a list of ancestors of self.
+
+=cut
+
+sub ancestors {
+  my ($self) = @_;
+
+  unless ($self->{_ancestors}) {
+    my @ancestors;
+    my $work = $self;
+    while ($work->parentid != -1) {
+      $work = $work->parent;
+      push @ancestors, $work;
+    }
+
+    $self->{_ancestors} = \@ancestors;
+  }
+
+  return @{$self->{_ancestors}};
+}
+
+=item is_descendant_of($ancestor)
+
+Return true if the supplied article is a descendant of self.
+
+=cut
+
+sub is_descendant_of {
+  my ($self, $ancestor) = @_;
+
+  for my $anc ($self->ancestors) {
+    return 1 if $anc->id == $ancestor->id;
+  }
+
+  return 0;
+}
+
 sub restricted_methods {
   my ($self, $name) = @_;
 
@@ -362,3 +459,21 @@ sub restricted_methods {
 }
 
 1;
+
+__END__
+
+=back
+
+=head1 BASE CLASSES
+
+L<BSE::TB::SiteCommon>
+
+L<BSE::TB::TagOwner>
+
+L<Squirrel::Row>
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
index 961475be1aa7040dadac0e87d6ea97557d74d402..2447b6d79dfb4ecccc598a836cf4636970a238f4 100644 (file)
@@ -10,7 +10,7 @@ use Carp qw(confess);
 use BSE::WebUtil qw(refresh_to_admin);
 use BSE::Util::HTML;
 
-our $VERSION = "1.005";
+our $VERSION = "1.006";
 
 # returns non-zero if the Regenerate button should work
 sub generate_button {
@@ -316,7 +316,9 @@ sub _common_one_extra {
       };
   }
 
-  my $content = BSE::Template->get_page($extra->{base}, $cfg, \%acts);
+  my $content = BSE::Template->get_page($extra->{base}, $cfg, \%acts,
+                                       undef, undef, $gen->variables);
+
   return wantarray ? ( $content, $article ) : $content;
 }
 
@@ -390,7 +392,8 @@ sub generate_base {
          };
       }
       $progress->($extra, "Generating $extra->{name}");
-      my $content = BSE::Template->get_page($extra->{base}, $cfg, \%acts);
+      my $content = BSE::Template->get_page($extra->{base}, $cfg, \%acts,
+                                           undef, undef, $gen->variables);
       my $outname = $extra->{outpath} . "/". $extra->{name};
       my $workname = $outname . ".work";
       _write_text($workname, $content, $cfg);
index 754c8927ed28384cbfdbe0c1acbfa22ada0b5112..428767182329eba35d31f690c7de3eec5b08ff1c 100644 (file)
@@ -2,7 +2,26 @@ package BSE::TB::SiteCommon;
 use strict;
 use Carp qw(confess);
 
-our $VERSION = "1.003";
+our $VERSION = "1.005";
+
+=head1 NAME
+
+BSE::TB::SiteCommon - methods common to the site and article objects
+
+=head1 SYNOPSIS
+
+  my @steps = $article->set_parents;
+  my @sections = $site->children;
+
+=head1 DESCRIPTION
+
+Provides methods common to the Article and BSE::TB::Site objects.
+
+=head1 USEFUL METHODS
+
+=over
+
+=cut
 
 sub step_parents {
   my ($self) = @_;
@@ -100,6 +119,37 @@ sub all_visible_catalogs {
   return grep $_->{generator} eq "Generate::Catalog", $self->all_visible_kids;
 }
 
+sub visible_kids {
+  my ($self) = @_;
+
+  return Articles->listedChildren($self->{id});
+}
+
+=item menu_kids
+
+Returns a list of children meant to be listed in menus.
+
+=cut
+
+sub menu_kids {
+  my ($self) = @_;
+
+  return grep $_->listed_in_menu, $self->visible_kids;
+}
+
+
+=item menu_kids
+
+Returns a list of allkids meant to be listed in menus.
+
+=cut
+
+sub all_menu_kids {
+  my ($self) = @_;
+
+  return grep $_->listed_in_menu, $self->all_visible_kids;
+}
+
 sub images {
   my ($self) = @_;
   require BSE::TB::Images;
@@ -109,7 +159,7 @@ sub images {
 sub children {
   my ($self) = @_;
 
-  return sort { $b->{displayOrder} <=> $b->{displayOrder} } 
+  return sort { $b->{displayOrder} <=> $a->{displayOrder} } 
     Articles->children($self->{id});
 }
 
@@ -324,3 +374,13 @@ sub set_image_order {
 }
 
 1;
+
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
index d1127e9403460b96225274bebd208611f6e29130..b226991beac85341cfd847121ab95289fb1edb46 100644 (file)
@@ -6,7 +6,40 @@ use strict;
 use BSE::TB::Tags;
 use BSE::TB::TagMembers;
 
-our $VERSION = "1.001";
+our $VERSION = "1.002";
+
+=head1 NAME
+
+BSE::TB::TagOwner - mixin for objects with tags
+
+=head1 SYNOPSIS
+
+  my $article = ...;
+
+  $article->set_tags([ qw/tag1 tag2/ ], \$error);
+  $article->remove_tags;
+
+  my @tags = $article->tag_objects;
+  my @tag_names = $article->tags;
+  my @tag_ids = $article->tag_ids;
+
+  if ($article->has_tags([ "tag1", "tag2" ])) {
+    ...
+  }
+
+=head1 DESCRIPTION
+
+This class is a mix-in that implements tags for the mixed-into object.
+
+=head1 METHODS PROVIDED
+
+=over
+
+=item set_tags(\@tags, \$error)
+
+Set the specified tags on the object, replacing all existing tags.
+
+=cut
 
 sub set_tags {
   my ($self, $rtags, $rerror) = @_;
@@ -69,31 +102,60 @@ sub set_tags {
   return 1;
 }
 
-# remove all tags
+=item remove_tags
+
+Remove all tags from the object.
+
+=cut
+
 sub remove_tags {
   my ($self) = @_;
 
   BSE::TB::TagMembers->remove_owned_by($self);
 }
 
+=item tag_objects
+
+Return all existing tags on the object as tag objects.
+
+=cut
+
 sub tag_objects {
   my ($self) = @_;
 
   return BSE::TB::Tags->getSpecial(object_tags => $self->tag_owner_type, $self->id);
 }
 
+=item tags
+
+Returns all existing tags on the object as tag names.
+
+=cut
+
 sub tags {
   my ($self) = @_;
 
   return map $_->name, $self->tag_objects;
 }
 
+=item tag_ids
+
+Returns all existing tags on the object as tag ids.
+
+=cut
+
 sub tag_ids {
   my ($self) = @_;
 
   return map $_->{id}, BSE::DB->single->run("Tag_ids.by_owner", $self->tag_owner_type, $self->id);
 }
 
+=item has_tags(\@tags)
+
+Check that all of the specified tags are on the object.
+
+=cut
+
 sub has_tags {
   my ($self, $rtags) = @_;
 
@@ -116,3 +178,30 @@ sub has_tags {
 }
 
 1;
+
+__END__
+
+=back
+
+=head1 REQUIRED METHODS
+
+These need to be implemented by the class that wants tags.
+
+=over
+
+=item tag_owner_type
+
+Return a short constant string identifying owner class of the tags.
+
+=item id
+
+The numeric id of the specific owner object of the tags.
+
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
+
index 113e0f29f8abbcf8b48201ee75a6fcc338dc5209..b62556b484bee7da65b3b3927e2f6b6aee4beb93 100644 (file)
@@ -4,7 +4,7 @@ use Squirrel::Template;
 use Carp qw(confess cluck);
 use Config ();
 
-our $VERSION = "1.006";
+our $VERSION = "1.007";
 
 sub templater {
   my ($class, $cfg, $rsets) = @_;
@@ -75,11 +75,11 @@ sub get_page {
 }
 
 sub replace {
-  my ($class, $source, $cfg, $acts) = @_;
+  my ($class, $source, $cfg, $acts, $vars) = @_;
 
   my $obj = $class->templater($cfg);
 
-  $obj->replace_template($source, $acts);
+  $obj->replace_template($source, $acts, undef, undef, $vars);
 }
 
 sub charset {
index e0cb0bf2062cb645d6d17a375efb60f0e5ef1ecc..35a5efc2aef3cf731f55c47513c7c7ad073cf811 100644 (file)
@@ -8,10 +8,11 @@ use BSE::Util::HTML;
 use BSE::Util::Tags qw(tag_article);
 use BSE::CfgInfo qw(custom_class);
 use BSE::Util::Iterate;
+use BSE::TB::Site;
 use base 'BSE::ThumbLow';
 use base 'BSE::TagFormats';
 
-our $VERSION = "1.006";
+our $VERSION = "1.007";
 
 my $excerptSize = 300;
 
@@ -24,13 +25,56 @@ sub new {
   }
   $opts{maxdepth} = $EMBED_MAX_DEPTH unless exists $opts{maxdepth};
   $opts{depth} = 0 unless $opts{depth};
-  return bless \%opts, $class;
+  $opts{vars} =
+    {
+     cfg => $opts{cfg},
+     bse =>
+     {
+      site => BSE::TB::Site->new,
+      url => 
+      ($opts{admin} || $opts{admin_links}
+       ? sub { $_[0]->admin }
+       : sub { $_[0]->link }
+      ),
+      admin => $opts{admin},
+      admin_links => $opts{admin_links},
+      dumper => sub {
+       require Data::Dumper;
+       return escape_html(Data::Dumper::Dumper(shift));
+      },
+     },
+    };
+  my $self = bless \%opts, $class;
+  $self->set_variable_class(articles => "Articles");
+
+  return $self;
 }
 
 sub cfg {
   $_[0]{cfg};
 }
 
+sub set_variable {
+  my ($self, $name, $value) = @_;
+
+  $self->{vars}{$name} = $value;
+
+  return 1;
+}
+
+sub set_variable_class {
+  my ($self, $name, $class) = @_;
+
+  require Squirrel::Template;
+  $self->set_variable($name => Squirrel::Template::Expr::WrapClass->new($class));
+}
+
+sub variables {
+  my ($self) = @_;
+
+  return $self->{vars};
+}
+
 # replace commonly used characters
 # like MS dumb-quotes
 # unfortunately some browsers^W^Wnetscape don't support the entities yet <sigh>
index 6c04b343b9b02bd1ad13d3a94c52fe2144e1cba5..01fa0c98a029a3e73c7bc77c46537a9dbc7a793c 100644 (file)
@@ -15,7 +15,7 @@ use BSE::Arrows;
 use Carp 'confess';
 use BSE::Util::Iterate;
 
-our $VERSION = "1.003";
+our $VERSION = "1.004";
 
 my $excerptSize = 300;
 
@@ -61,7 +61,8 @@ sub generate_low {
   my %acts;
   %acts = $self -> baseActs($articles, \%acts, $article, $embedded);
 
-  my $page = BSE::Template->replace($template, $self->{cfg}, \%acts);
+  my $page = BSE::Template->replace($template, $self->{cfg}, \%acts,
+                                   $self->variables);
 
   %acts = (); # try to destroy any circular refs
 
@@ -362,6 +363,8 @@ sub baseActs {
 
   my $cfg = $self->{cfg} || BSE::Cfg->single;
 
+  $self->set_variable(article => $article);
+  $self->set_variable(embedded => $embedded);
   # used to generate the list (or not) of children to this article
   my $child_index = -1;
   my @children = $articles->listedChildren($article->{id});
index 358a7eb6e6a10e4432e5f56393ca55bb67f23e9c..6ec7f437161ed09219ce56c002479cb158a2ce17 100644 (file)
@@ -7,7 +7,10 @@ use strict;
 my @targets =
   (
    'access.html',
+   'Article.html',
    'bse.html',
+   'BSE::TB::SiteCommon.html',
+   'BSE::TB::TagOwner.html',
    'bugs.html',
    'templates.html',
    'Generate.html',
index 5c529a85560fc63550ac1ca71ec5566895f0de6d..e54a66bff1413cfa2428467df0b5916280ac2bd3 100644 (file)
 <:include include/cart_sidebar.tmpl:>
 <:or Cfg:><:eif Cfg:>
 <:or Dynamic:>
-            <:iterator begin level1:>  
+           <:.set level1_menu = [ bse.site.menu_kids ] :>
+            <:.for level1 in level1_menu :>  
             <table width="100%" border="0" cellspacing="0" cellpadding="0">
               <tr> 
                 <td> 
                   <table width="100%" border="0" cellspacing="0" cellpadding="0">
-                    <:if Ancestor level1:>
+                    <:.if article.is_descendant_of(level1):>
                     <tr> 
-                      <td height="19" width="100%" nowrap bgcolor="#999999">&nbsp;<:ifLevel1 link:><a href="<:url level1:>"><:or:><:eif:><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#FFFFFF"><:level1 
-                        title:></font></b><:ifLevel1 link:></a><:or:><:eif:> </td>
+                      <td height="19" width="100%" nowrap bgcolor="#999999">&nbsp;<:.if level1.link:><a href="<:= bse.url(level1) |html:>"><:.end if:><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#FFFFFF"><:= level1.title
+                       |html :></font></b><:.if level1.link:></a><:.end if:> </td>
                     </tr>
-                    <:or Ancestor:>
+                    <:.else:>
                     <tr> 
-                      <td height="19" width="100%" nowrap bgcolor="#CCCCCC">&nbsp;<:ifLevel1 link:><a href="<:url level1:>"><:or:><:eif:><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><:level1 
-                        title:></font></b><:ifLevel1 link:></a><:or:><:eif:> </td>
+                      <td height="19" width="100%" nowrap bgcolor="#CCCCCC">&nbsp;<:.if level1.link:><a href="<:= bse.url(level1) :>"><:.end if:><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><:= level1.title |html:></font></b><:.if level1.link:></a><:.end if:> </td>
                     </tr>
-                    <:eif Ancestor:>
+                    <:.end if:>
                   </table>
                 </td>
               </tr>
-              <:if Ancestor level1:>
+              <:.if article.is_descendant_of(level1) :>
                <tr> 
                 <td>
-                 <:if Level2:> 
+                <:.set level2_menu = [ level1.menu_kids ] :>
+                 <:# = bse.dumper(level2_menu) :>
+                 <:.if level2_menu.size != 0:> 
                   <table width="100%" border="0" cellspacing="0" cellpadding="3">
-                    <:iterator begin level2:>
-                    <:ifAncestor level2:>
+                    <:.for level2 in level2_menu:>
+                    <:.if article.is_descendant_of(level2) :>
                      <tr> 
-                      <td bgcolor="#FFFFFF"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:url level2:>"><:level2 title:></a></font> 
+                      <td bgcolor="#FFFFFF"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:= bse.url(level2) |html:>"><:= level2.title |html:></a></font> 
                         </td>
                      </tr>
-                     <:or:>
+                     <:.else:>
                      <tr> 
-                      <td bgcolor="#EEEEEE"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:url level2:>"><:level2 title:></a></font> 
+                      <td bgcolor="#EEEEEE"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:= bse.url(level2) |html:>"><:= level2.title |html:></a></font> 
                         </td>
                      </tr>
-                     <:eif:>
-                        <:iterator end level2:>
+                     <:.end if:>
+                        <:.end for:>
                   </table>
-            <:or Level2:> 
-            <:eif Level2:>
+            <:.end if:>
                 </td>
               </tr>
-<:or Ancestor:>
-<:eif Ancestor:>
+<:.end if:>
               <tr> 
                 <td><img src="/images/trans_pixel.gif" width="1" height="1" alt="spacer"></td>
               </tr>
             </table>
-<:iterator separator level1:><:iterator end level1:> 
+<:.end for:>
 <:eif Dynamic:>
             <:embed 5:> </td>
         </tr>
index b9147f4621569a21f593f95551b82a2d0c646944..8526990743480e5bffd404dd78bd4beb97ca4842 100644 (file)
@@ -76,11 +76,17 @@ template_test "children_of", $top, <<TEMPLATE, <<EXPECTED;
 <:iterator begin children_of $parent->{id}:><:
 ofchild title:>
 <:iterator end children_of:>
+<:-.set myart = articles.getByPkey($parent->{id}):>
+<:-.for a in [ myart.visible_kids ]:>
+<:-= a.title |html :>
+<:.end for-:>
 TEMPLATE
 Three
 Two
 One
-
+Three
+Two
+One
 EXPECTED
 
 template_test "allkids_of", $top, <<TEMPLATE, <<EXPECTED;