diff --git a/www/index.pl b/www/index.pl
index ccc6cf1..972ce5f 100755
--- a/www/index.pl
+++ b/www/index.pl
@@ -398,9 +398,7 @@ TUWF::get '/info/about' => sub {
Will get the man page from a specific package version (e.g. /man/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync)
-
Currently, the last three URLs will perform a redirect to the
- appropriate permalink URL, but this may change in the future.
- In all URLs where an optional .<section> can be provided,
+
In all URLs where an optional .<section> can be provided,
the search is performed as a prefix match. For example, /cat.3 will provide the cat.3tcl man page if
no exact cat.3 version is available. Linking to the full
@@ -631,9 +629,18 @@ TUWF::get qr{/([^/]+)/([0-9a-f]{8})/src} => sub {
};
-sub _man_nav {
+sub man_nav_ {
my($man, $toc) = @_;
+ my @systems = tuwf->dbAlli('
+ SELECT DISTINCT p.system
+ FROM packages p
+ JOIN package_versions v ON v.package = p.id
+ JOIN files f ON f.pkgver = v.id
+ JOIN mans m ON m.id = f.man
+ WHERE m.name =', \$man->{name}, 'AND m.section =', \$man->{section}
+ )->@*;
+
my @sect = map $_->{section}, tuwf->dbAlli(
'SELECT DISTINCT section FROM mans WHERE name =', \$man->{name}, 'ORDER BY section'
)->@*;
@@ -646,13 +653,32 @@ sub _man_nav {
WHERE m.name =", \$man->{name}, 'AND m.section =', \$man->{section}, "
ORDER BY substring(l.locale from '^[^.]+') NULLS FIRST"
)->@*;
- return if !@sect && !@lang && !@$toc;
- # TODO: This is ugly, especially because clicking on a translation or
- # section, you can end up with a man page that is nowhere close to the man
- # page you're currently reading. Opening a version selector box might be a
- # better alternative.
- div_ id => 'nav', sub {
+ nav_ sub {
+ form_ action => "/sysredir/$man->{name}.$man->{section}", method => 'get',
+ onsubmit => 'location.href="/man/"+system_select[system_select.selectedIndex].value+"/'.$man->{name}.'.'.$man->{section}.'";return false',
+ sub {
+ my %names;
+ push $names{$_->{name}}->@*, $_ for map sysbyid->{$_->{system}}, sort { $b->{system} <=> $a->{system} } @systems;
+ select_ id => 'system_select', name => 'system', sub {
+ for (sort { ($names{$b}->@* == 1) <=> ($names{$a}->@* == 1) || $a cmp $b } keys %names) {
+ my $s = $names{$_};
+ if (@$s == 1) {
+ option_ value => $s->[0]{short}, selected => $s->[0]{id} == $man->{system}?'':undef, $s->[0]{full};
+ next;
+ }
+ optgroup_ label => $_, sub {
+ option_ value => $_->{short}, selected => $_->{id} == $man->{system}?'':undef, $_->{full} for @$s;
+ };
+ }
+ };
+ input_ type => 'submit', value => 'Go';
+ } if @systems > 1;
+
+ # TODO: This is ugly, especially because clicking on a translation or
+ # section, you can end up with a man page that is nowhere close to the
+ # man page you're currently reading. Sections or languages available
+ # for the currently selected system should be highlighted.
if(@sect > 1) {
b_ 'Sections';
p_ sub {
@@ -719,22 +745,8 @@ sub soelim {
}
-# This one has to go before the other mappings, to ensure that links work for
-# man pages called 'pkg' or 'man'. This also means that we can't have a
-# system named 8 hex digits, but at least that's easy to guarantee. :)
-TUWF::get qr{/(?[^/]+)(?:/(?[0-9a-f]{8}))?} => sub {
- my $name = normalize_name tuwf->capture('name');
- my $shorthash = tuwf->capture('hash');
-
- # Unfortunately, even in the permalink format with the hash, we don't know
- # from which package we're supposed to get the man page. This info is
- # needed in order to do .so substitution, so we can substitute files from
- # the same package as the requested man page. Use the man_pref logic here
- # to deterministically select a good package.
- my($man, undef) = $shorthash
- ? man_pref undef, sql 'm.name =', \$name, 'AND f.shorthash =', shorthash_to_int($shorthash)
- : man_pref_name $name, 'true';
- return tuwf->resNotFound() if !$man->{name};
+sub man_page {
+ my($man) = @_;
my $content = tuwf->dbRowi('SELECT encode(hash, \'hex\') AS hash, content FROM contents WHERE id =', \$man->{content});
my $fmt = ManUtils::html ManUtils::fmt_block soelim $man->{verid}, $content->{content};
@@ -757,8 +769,9 @@ TUWF::get qr{/(?[^/]+)(?:/(?[0-9a-f]{8}))?} => sub {
);
tuwf->resLastMod($man->{released});
- framework_ title => $name, sub {
- _man_nav $man, \@toc;
+ framework_ title => $man->{name}, mainclass => 'manpage', sub {
+ man_nav_ $man, \@toc;
+ # TODO: Replace the 'versions' and 'locations' functionality with non-JS alternatives.
div_ id => 'manbuttons', sub {
h1_ $man->{name};
ul_ 'data-hash' => $content->{hash},
@@ -772,11 +785,61 @@ TUWF::get qr{/(?[^/]+)(?:/(?[0-9a-f]{8}))?} => sub {
}
};
div_ id => 'manres', class => 'hidden', '';
-
- div_ id => 'contents', sub {
- pre_ sub { lit_ $fmt }
- }
+ pre_ sub { lit_ $fmt };
};
+}
+
+
+# This one has to go before the other mappings, to ensure that links work for
+# man pages called 'pkg' or 'man'. This also means that we can't have a
+# system named 8 hex digits, but at least that's easy to guarantee. :)
+TUWF::get qr{/(?[^/]+)(?:/(?[0-9a-f]{8}))?} => sub {
+ my $name = normalize_name tuwf->capture('name');
+ my $shorthash = tuwf->capture('hash');
+
+ # Unfortunately, even in the permalink format with the hash, we don't know
+ # from which system and package we're supposed to get the man page. This
+ # info is used in the UI and needed in order to do .so substitution, so we
+ # can substitute files from the same package as the requested man page. Use
+ # the man_pref logic here to deterministically select a good package.
+ my($man, undef) = $shorthash
+ ? man_pref undef, sql 'm.name =', \$name, 'AND f.shorthash =', shorthash_to_int($shorthash)
+ : man_pref_name $name, 'true';
+ return tuwf->resNotFound() if !$man->{name};
+
+ man_page $man;
+};
+
+
+TUWF::get qr{/man/([^/]+)/(.+)} => sub {
+ my($sys, $path) = tuwf->captures(1,2);
+
+ # Path can be:
+ # 1.
+ # 2. //
+ # 3. ///
+
+ # $sys can be either a full system 'short' name, or a prefix (e.g. 'debian' meaning 'any debian-* version')
+ my $sysid = sysbyshort->{$sys};
+ $sysid = $sysid ? [$sysid->{id}] : [ map sysbyshort->{$_}{id}, grep /^\Q$sys\E-/, keys sysbyshort->%* ];
+ return tuwf->resNotFound if !@$sysid;
+
+ my $shorthash = $path =~ s{/([a-fA-F0-9]{8})$}{} ? $1 : undef;
+ my $man;
+ if($path !~ m{/}) { # (1)
+ ($man) = man_pref_name $path, sql 's.id IN', $sysid;
+
+ } else {
+ $path =~ s{/([^/]+)$}{};
+ my $name = $1;
+
+ my($pkg, $ver) = pkg_frompath sql('system IN', $sysid), $path; # Handles (2) and (3)
+ return tuwf->resNotFound if !$pkg;
+
+ ($man) = man_pref_name $name, sql 's.id IN', $sysid, 'AND p.id =', \$pkg->{id}, $ver ? ('AND v.version =', \$ver) : ();
+ }
+ return tuwf->resNotFound if !$man;
+ man_page $man;
};
@@ -797,11 +860,10 @@ TUWF::get qr{/pkg/([^/]+)} => sub {
'SELECT id, system, name, category, dead FROM', $packages_with_man, 'p WHERE', $where, 'ORDER BY name, category'
);
- my $title = $sys->{name}.($sys->{release}?" $sys->{release}":"");
- framework_ title => $title, mainclass => 'pkglist', sub {
+ framework_ title => $sys->{full}, mainclass => 'pkglist', sub {
div_ sub {
div_ sub {
- h1_ $title;
+ h1_ $sys->{full};
};
nav_ class => 'charselect', sub {
for('all', 0, 'a'..'z') {
@@ -859,11 +921,11 @@ TUWF::get qr{/pkg/([^/]+)/(.+)} => sub {
# Latest version of this package determines last modification date of the page.
tuwf->resLastMod($vers->[0]{released});
- my $sysname = $sys->{name}.($sys->{release}?" $sys->{release}":"");
my $subtitle = " / $pkg->{category} / $pkg->{name}";
- framework_ title => "$sysname$subtitle $sel->{version}", mainclass => 'pkgpage', sub {
+ my $pkgpath = "$sys->{short}/$pkg->{category}/$pkg->{name}";
+ framework_ title => "$sys->{full}$subtitle $sel->{version}", mainclass => 'pkgpage', sub {
h1_ sub {
- a_ href => "/pkg/$sys->{short}", $sysname;
+ a_ href => "/pkg/$sys->{short}", $sys->{full};
txt_ $subtitle;
};
@@ -872,7 +934,7 @@ TUWF::get qr{/pkg/([^/]+)/(.+)} => sub {
h2_ 'Versions';
ul_ sub {
li_ sub {
- a_ href => "/pkg/$sys->{short}/$pkg->{category}/$pkg->{name}/$_->{version}", $_->{version} if $_ != $sel;
+ a_ href => "/pkg/$pkgpath/$_->{version}", $_->{version} if $_ != $sel;
b_ " $_->{version}" if $_ == $sel;
small_ " $_->{released}";
} for(@$vers);
@@ -881,15 +943,17 @@ TUWF::get qr{/pkg/([^/]+)/(.+)} => sub {
section_ sub {
h2_ "Manuals for version $sel->{version}";
- paginate_ "/pkg/$sys->{short}/$pkg->{category}/$pkg->{name}/$sel->{version}?p=", $count, 200, $p;
+ paginate_ "/pkg/$pkgpath/$sel->{version}?p=", $count, 200, $p;
ul_ sub {
li_ sub {
- a_ href => "/$_->{name}/".shorthash_to_hex($_->{shorthash}), "$_->{name}($_->{section})";
+ # BUG: This URL should include the shorthash (or locale, at least),
+ # because the same package may have multiple pages with the same name and section.
+ a_ href => "/man/$pkgpath/$sel->{version}/$_->{name}.$_->{section}", "$_->{name}($_->{section})";
b_ " $_->{locale}" if $_->{locale};
small_ " $_->{filename}";
} for(@$mans);
};
- paginate_ "/pkg/$sys->{short}/$pkg->{category}/$pkg->{name}/$sel->{version}?p=", $count, 200, $p;
+ paginate_ "/pkg/$pkgpath/$sel->{version}?p=", $count, 200, $p;
};
};
}
@@ -906,37 +970,9 @@ TUWF::get qr{/browse/([^/]+)/([^/]+)(?:/([^/]+))?} => sub {
tuwf->resRedirect("/pkg/$sys->{short}/$pkgs->{category}/$name".($ver ? "/$ver" :''), 'perm');
};
-# Redirects for canonical URLs
-TUWF::get qr{/man/([^/]+)/(.+)} => sub {
- my($sys, $path) = tuwf->captures(1,2);
- # Path can be:
- # 1.
- # 2. //
- # 3. ///
-
- # $sys can be either a full system 'short' name, or a prefix (e.g. 'debian' meaning 'any debian-* version')
- my $sysid = sysbyshort->{$sys};
- $sysid = $sysid ? [$sysid->{id}] : [ map sysbyshort->{$_}{id}, grep /^\Q$sys\E-/, keys sysbyshort->%* ];
- return tuwf->resNotFound if !@$sysid;
-
- my $man;
- if($path !~ m{/}) { # (1)
- ($man) = man_pref_name $path, sql 's.id IN', $sysid;
-
- } else {
- $path =~ s{/([^/]+)$}{};
- my $name = $1;
-
- my($pkg, $ver) = pkg_frompath sql('system IN', $sysid), $path; # Handles (2) and (3)
- return tuwf->resNotFound if !$pkg;
-
- ($man) = man_pref_name $name, sql 's.id IN', $sysid, 'AND p.id =', \$pkg->{id}, $ver ? ('AND v.version =', \$ver) : ();
- }
- return tuwf->resNotFound if !$man;
-
- tuwf->resRedirect("/$man->{name}/".shorthash_to_hex($man->{shorthash}), 'temp');
-};
+# Redirect for the system selection box, for visitors who have disabled JS.
+TUWF::get qr{/sysredir/([^/]+)} => sub { tuwf->resRedirect('/man/'.(tuwf->reqGet('system')//'arch').'/'.tuwf->capture(1), 'temp') };
# Redirect for a specific language for a man page.
diff --git a/www/man.css b/www/man.css
index c761a7d..a1dbe15 100644
--- a/www/man.css
+++ b/www/man.css
@@ -76,16 +76,21 @@ main.thin { max-width: 700px; margin: 0 auto }
#manres table { margin: 2px 10px; }
#manres table tr td:nth-child(1) { min-width: 80px }
-#nav { background: #f0f8ff; color: #036; float: right; padding: 8px; width: 250px; margin-bottom: 10px; border-radius: 8px; }
-#nav b { text-transform: uppercase; font-size: 13px }
-#nav p { margin: 3px 5px 20px 5px }
-#nav p a, #nav p i { padding: 3px 5px; font-size: 13px; font-style: normal; text-decoration: none;}
-#nav p a:hover, #nav p i { background: #cde; border-radius: 5px }
-#nav ul { list-style-type: none; margin: 3px 10px 0 20px }
-#nav ul li a { overflow: hidden; margin-left: -10px; text-decoration: none; text-transform: capitalize }
+.manpage nav { background: #f0f8ff; color: #036; float: right; padding: 8px; width: 250px; margin-bottom: 10px; border-radius: 8px; }
+.manpage nav b { text-transform: uppercase; font-size: 13px }
+.manpage nav p { margin: 3px 5px 20px 5px }
+.manpage nav p a,
+.manpage nav p i { padding: 3px 5px; font-size: 13px; font-style: normal; text-decoration: none;}
+.manpage nav p a:hover,
+.manpage nav p i { background: #cde; border-radius: 5px }
+.manpage nav ul { list-style-type: none; margin: 3px 10px 0 20px }
+.manpage nav ul li a { overflow: hidden; margin-left: -10px; text-decoration: none; text-transform: capitalize }
+.manpage nav form { margin: 0 0 10px 0 }
+.manpage nav select { width: 200px }
+.manpage nav input { width: 40px }
-#contents { margin: 10px 0 0 0 }
+pre { margin: 10px 0 0 0 }
pre, pre * { font-family: "Lucida Console", Monospace; font-size: 15px }
pre b, pre em, pre a { color: #369; font-weight: normal; text-decoration: none }
pre em { font-style: italic }