Author: amc
Date: Thu Nov 10 21:02:20 2011
New Revision: 1200544
URL: http://svn.apache.org/viewvc?rev=1200544&view=rev
Log:
Side tree nav, attempt 1.
Modified:
trafficserver/site/branches/ats-cms/lib/view.pm
trafficserver/site/branches/ats-cms/templates/docs_page.html
Modified: trafficserver/site/branches/ats-cms/lib/view.pm
URL:
http://svn.apache.org/viewvc/trafficserver/site/branches/ats-cms/lib/view.pm?rev=1200544&r1=1200543&r2=1200544&view=diff
==============================================================================
--- trafficserver/site/branches/ats-cms/lib/view.pm (original)
+++ trafficserver/site/branches/ats-cms/lib/view.pm Thu Nov 10 21:02:20 2011
@@ -39,14 +39,25 @@ sub _SplitContentName {
return @zret;
}
+# This is basically File::Spec::catdir except it makes a relative path
+# of just 'dir' if the base path is empty.
+sub _append_to_path {
+ my ($path, $dir) = @_;
+ return $path ? File::Spec->catdir($path, $dir) : $dir;
+}
+
package view::Source;
# A source / content file. This is a terminal in the documentation tree.
# It has a map of language tags -> original file.
-# _LANGMAP -> Hash from language tag to source file.
+# _LANGMAP -> Hash from language tag to source file data.
+# _FILE -> Local file name.
+# _LINK -> File name for HTML links.
+# _VARS -> Internal file variables.
+#
# _STEM -> The stem for this source.
# _PATH -> Path of the directory containing this source.
-# _VARS -> Template variables to be used during generation.
+# _VARS -> External variables for stem.
sub new {
my ($self, $path, $stem) = @_;
@@ -69,6 +80,7 @@ sub stem { return $_[0]->{_STEM}; }
sub path { return $_[0]->{_PATH}; }
# This is a convenience so we don't have to check for being a node.
sub srcCount { return 0; }
+sub isTop { return 0; }
sub parent {
my ($self) = @_;
@@ -90,37 +102,49 @@ sub vars {
return $zret;
}
-sub setVars {
- my ($self, $vars) = @_;
- $self->{_VARS}{keys %$vars} = values %$vars;
- return $self;
+sub setFileForLang {
+ my ($self, $file, $lang) = @_;
+ my $link = join('.', (view::_SplitContentName($file))[0,1], 'html');
+ $self->{_LANGMAP}{$lang} = {
+ _FILE => $file,
+ _LINK => $link
+ };
+}
+
+# Access the language specific data
+sub langToData {
+ my ($self, $lang) = @_;
+ my $zret = $self->{_LANGMAP}{$lang} ||
$self->{_LANGMAP}{view::DEFAULT_LANG()};
+ die "Stem '", $self->stem, "' in '", $self->{_PATH}, "' does not have
language '$lang' or the default '", view::DEFAULT_LANG(), "'.\n" unless $zret;
+ # Fault in the file at this point.
+ if (not $zret->{_VARS}) {
+ my %vars = %{$self->vars}; # copy external variables over.
+ my $var_path = File::Spec->catfile($self->path, $zret->{_FILE});
+ view::read_text_file $var_path, \%vars; # add file internal vars.
+ $zret->{_VARS} = \%vars;
+ }
+ return $zret;
}
# Get/Set the file for lang. This should be the local file name, not a path.
sub langToFile {
my ($self, $lang, $file) = @_;
- my $zret = $self->{_LANGMAP}{$lang};
- if (scalar @_ > 2) {
- $self->{_LANGMAP}{$lang} = $file;
- } else {
- $zret = $self->{_LANGMAP}{view::DEFAULT_LANG()} unless $zret;
- die "Stem '", $self->stem, "' in '", $self->{_PATH}, "' does not have
language '$lang' or the default '", view::DEFAULT_LANG(), "'.\n" unless $zret;
- }
- return $zret;
+ return $self->langToData($lang)->{_FILE};
}
-# Set the link name for @a lang.
+# Get the link name for @a lang.
sub langToLink {
my ($self, $lang) = @_;
- my $file = $self->langToFile($lang);
- if ($file) {
- my $stem = (view::_SplitContentName($file))[0];
- $file = "$stem.$lang.html";
- }
- return $file;
+ return $self->langToData($lang)->{_LINK};
+}
+
+# Get the variables (including content) for a language.
+sub langToVars {
+ return $_[0]->langToData($_[1])->{_VARS};
}
-# Just set the lang tag map from another instance.
+# Set the lang map / data directly.
+# Used by stem loading logic.
sub copyLangMap {
my ($self, $that) = @_;
$self->{_LANGMAP} = $that->{_LANGMAP};
@@ -132,12 +156,37 @@ sub langList {
return keys %{$self->{_LANGMAP}};
}
+# Compute a relative path from this source to another.
+sub pathTo {
+ my ($self, $dest) = @_;
+ my @spath = File::Spec->splitdir($self->path);
+ my @dpath = File::Spec->splitdir($dest->path);
+ my $rpath = '';
+
+ # strip off matching ancestors from the top.
+ while (scalar @spath and scalar @dpath and $spath[0] eq $dpath[0]) {
+ shift @spath;
+ shift @dpath;
+ }
+ # Now work up the source path.
+ while (scalar @spath) {
+ $rpath = view::_append_to_path($rpath, '..');
+ pop @spath;
+ }
+ # Then back down the destination.
+ while (scalar @dpath) {
+ $rpath = view::_append_to_path($rpath, shift @dpath);
+ }
+ return $rpath;
+}
+
package view::Node;
our @ISA = ( 'view::Source' );
# Boolean constants
use constant TRUE => 1;
use constant FALSE => 0;
use Carp;
+use Clone;
# Map from directory paths to Nodes.
our %Locations;
@@ -167,11 +216,12 @@ sub isTop {
return $zret;
}
-# Because File::Spec::updir just add a '..' to the end.
+# Because File::Spec::updir just adds a '..' to the end.
sub ParentDir {
my ($path) = @_;
my @d = File::Spec->splitdir($path);
my $p;
+ # Bizarre but it handles emtpy directories.
do {
$p = pop @d;
} while scalar @d and not $p;
@@ -253,7 +303,7 @@ sub _LoadStems{
} elsif (not ref $src) {
die "Stem '$stem' used for both files and directory in
'$dir'.\n";
}
- $src->langToFile($lang, $name);
+ $src->setFileForLang($name, $lang);
}
}
}
@@ -336,10 +386,11 @@ sub GetLocation {
$node = _LoadPath($dir);
$Locations{$dir} = $node;
if (not $node->isTop) {
- my $parent = $node->parent;
+ my $parent = $node->parent; # magic recursion happens here.
my %locals = %{$node->vars}; # cache local vars.
- %{$node->vars} = %{$parent->vars}; # set all parent values.
- $node->vars->{keys %locals} = values %locals;
+ $node->vars(Clone::clone($parent->vars)); # copy parent values.
+ # overwrite parent values with locals.
+ @{$node->vars->{keys %locals}} = values %locals;
}
}
return $node;
@@ -407,8 +458,9 @@ sub single_narrative {
my ($src, $lang) = view::Node::GetSource($file);
$args{langs} = langs($src, $lang);
$args{lang} = $lang;
- $args{keys %{$src->vars}} = values %{$src->vars}; # override with source
variables.
- read_text_file $file, \%args;
+ # copy over file local vars, including content.
+ my $fvars = $src->langToVars($lang);
+ @args{keys %$fvars} = values %$fvars;
nav_links($src, \%args) if $args{headers}{navigation};
return Dotiac::DTL::Template($template)->render(\%args), html => \%args;
@@ -539,11 +591,37 @@ sub breadcrumbs {
# --------------
-# This is basically File::Spec::catdir except it forces an absolute path if
-# the current path is empty.
-sub append_to_path {
- my ($path, $dir) = @_;
- return $path ? File::Spec->catdir($path, $dir) : $dir;
+# Generate a navigation subtree starting at this node.
+# Also need the language and relative path.
+sub nav_sub_tree {
+ my ($src, $target, $lang) = @_;
+ my $text = '<li>';
+ my $rpath = $src->pathTo($target);
+
+ $text .= '<a href="';
+ $text .= _append_to_path($rpath, $target->langToLink($lang));
+ $text .= '" >';
+ $text .= $target->langToVars($lang)->{headers}{title} || '<strong>Title
Missing</strong>';
+ $text .= '</a>';
+
+ my $n = $target->srcCount;
+ if ($n) {
+ $text .= '<ul>';
+ for (my $i = 0 ; $i < $n ; ++$i) {
+ $text .= nav_sub_tree($src, $target->srcAt($i), $lang);
+ }
+ $text .= '</ul>';
+ }
+
+ $text .= '</li>';
+ return $text;
+}
+
+# Compute the full tree containing this node.
+sub nav_full_tree {
+ my ($node, $lang) = @_;
+ my $top = $node->top;
+ return '<ul>' . nav_sub_tree($node, $top, $lang) . '</ul>';
}
# Args:
@@ -555,8 +633,8 @@ sub next_link {
my ($node, $idx, $lang, $rpath) = @_;
my $other = $node->srcAt($idx);
my $url = '';
- $url = append_to_path($rpath, $other->stem) if $other->isa('view::Node');
- $url = append_to_path($url, $other->langToLink($lang));
+ $url = _append_to_path($rpath, $other->stem) if $other->isa('view::Node');
+ $url = _append_to_path($url, $other->langToLink($lang));
return $url;
}
@@ -571,11 +649,11 @@ sub right_leaf {
while (1) {
if ($src->srcCount > 0) {
# src is a directory with multiple nodes, descend in to it.
- $rpath = append_to_path($rpath, $src->stem);
+ $rpath = _append_to_path($rpath, $src->stem);
$node = $src;
$src = $node->srcAt($node->srcCount - 1);
} else { # we've hit the bottom, finish.
- $rpath = append_to_path($rpath, $stem) if $src->isa('view::Node');
+ $rpath = _append_to_path($rpath, $stem) if $src->isa('view::Node');
$rpath = $rpath ? File::Spec->catfile($rpath,
$src->langToLink($lang)) : $src->langToLink($lang);
last;
}
@@ -602,7 +680,7 @@ sub auto_nav {
my $bpath = $src->isa('view::Node') ? '..' : '';
my $idx = $parent->indexOfStem($src->stem);
if (0 == $idx) { # back from first stem is parent content
- $back_url = append_to_path($bpath, $parent->langToLink($lang));
+ $back_url = _append_to_path($bpath, $parent->langToLink($lang));
} else {
$back_url = right_leaf($parent, $parent->srcAt($idx-1)->stem,
$lang, $bpath);
}
@@ -626,11 +704,10 @@ sub auto_nav {
my $n = $parent->srcCount;
if ($idx < $n - 1 ) {
$next_url = next_link($parent, $idx+1, $lang, $rpath);
- } else {
- $rpath = append_to_path($rpath, '..');
}
}
last if $parent->isTop;
+ $rpath = _append_to_path($rpath, '..');
$src = $parent;
$parent = $src->parent;
}
@@ -712,6 +789,8 @@ sub nav_links {
my $auto_navs = auto_nav($src, $lang);
$args->{nav} = $auto_navs if @$auto_navs;
}
+
+ $args->{nav_tree} = nav_full_tree($src, $lang);
}
# Arg: Target file path.
Modified: trafficserver/site/branches/ats-cms/templates/docs_page.html
URL:
http://svn.apache.org/viewvc/trafficserver/site/branches/ats-cms/templates/docs_page.html?rev=1200544&r1=1200543&r2=1200544&view=diff
==============================================================================
--- trafficserver/site/branches/ats-cms/templates/docs_page.html (original)
+++ trafficserver/site/branches/ats-cms/templates/docs_page.html Thu Nov 10
21:02:20 2011
@@ -79,6 +79,7 @@
</div>
<div class="fourcol last">
{{ global_nav|markdown }}
+ {% if nav_tree %}{{ nav_tree|safe }}{% endif %}
</div>
</div>