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
@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
customInt1 customInt2 customInt3 customInt4 menu);
}
+=item section
+
+Return the article's section.
+
+=cut
+
sub section {
my ($self) = @_;
return $section;
}
+=item parent
+
+Return the article's parent.
+
+=cut
+
sub parent {
my ($self) = @_;
$self->{parentid} == -1 and return;
$self->{cached_dynamic} = $dynamic;
}
+=item is_dynamic
+
+Return true if the article is rendered dynamically.
+
+=cut
+
sub is_dynamic {
$_[0]{cached_dynamic};
}
return $link;
}
+=item admin
+
+Return the admin link for the article.
+
+=cut
+
sub admin {
my ($self) = @_;
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) = @_;
}
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
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 {
};
}
- 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;
}
};
}
$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);
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) = @_;
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;
sub children {
my ($self) = @_;
- return sort { $b->{displayOrder} <=> $b->{displayOrder} }
+ return sort { $b->{displayOrder} <=> $a->{displayOrder} }
Articles->children($self->{id});
}
}
1;
+
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
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) = @_;
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) = @_;
}
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
+
use Carp qw(confess cluck);
use Config ();
-our $VERSION = "1.006";
+our $VERSION = "1.007";
sub templater {
my ($class, $cfg, $rsets) = @_;
}
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 {
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;
}
$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>
use Carp 'confess';
use BSE::Util::Iterate;
-our $VERSION = "1.003";
+our $VERSION = "1.004";
my $excerptSize = 300;
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
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});
my @targets =
(
'access.html',
+ 'Article.html',
'bse.html',
+ 'BSE::TB::SiteCommon.html',
+ 'BSE::TB::TagOwner.html',
'bugs.html',
'templates.html',
'Generate.html',
<: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"> <: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"> <:.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"> <: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"> <:.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>
<: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;