www: Replace "versions" tab with separate page
This gets rid of the last remaining feature that only worked with Javascript.
This commit is contained in:
parent
962a7c848a
commit
18b9666e32
3 changed files with 94 additions and 397 deletions
205
www/index.pl
205
www/index.pl
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use v5.26;
|
||||
use warnings;
|
||||
use TUWF ':html5_', ':xml', 'uri_escape';
|
||||
use TUWF ':html5_', 'uri_escape';
|
||||
use POSIX 'ceil';
|
||||
use List::Util 'uniq', 'min';
|
||||
use SQL::Interp 'sql', 'sql_interp';
|
||||
|
|
@ -200,6 +200,19 @@ sub man_pref_name {
|
|||
}
|
||||
|
||||
|
||||
sub man_languages {
|
||||
my($name, $sect) = @_;
|
||||
[ map $_->{lang}, tuwf->dbAlli(
|
||||
"SELECT DISTINCT substring(l.locale from '^[^.]+') AS lang
|
||||
FROM files f
|
||||
JOIN mans m ON m.id = f.man
|
||||
JOIN locales l ON l.id = f.locale
|
||||
WHERE m.name =", \$name, 'AND m.section =', \$sect, "
|
||||
ORDER BY substring(l.locale from '^[^.]+') NULLS FIRST"
|
||||
)->@* ];
|
||||
}
|
||||
|
||||
|
||||
sub framework_ {
|
||||
my $content = pop;
|
||||
my(%o) = @_;
|
||||
|
|
@ -226,7 +239,6 @@ sub framework_ {
|
|||
};
|
||||
span_ 'all manual pages are copyrighted by their respective authors.';
|
||||
};
|
||||
script_ type => 'text/javascript', src => '/man.js?2', '';
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -290,7 +302,7 @@ TUWF::get '/' => sub {
|
|||
framework_ title => 'Man Pages Archive', mainclass => 'thin', sub {
|
||||
h1_ 'Welcome to Manned.org';
|
||||
h2_ 'The archive for man pages';
|
||||
lit sprintf <<' _', map num($stats->{$_}), qw|hashes mans files packages|;
|
||||
lit_ sprintf <<' _', map num($stats->{$_}), qw|hashes mans files packages|;
|
||||
<p>
|
||||
Indexing <b>%s</b> versions of <b>%s</b> manual pages found in
|
||||
<b>%s</b> files of <b>%s</b> packages.
|
||||
|
|
@ -354,7 +366,7 @@ TUWF::get '/' => sub {
|
|||
TUWF::get '/info/about' => sub {
|
||||
framework_ title => 'About', mainclass => 'thin', sub {
|
||||
h1_ 'About Manned.org';
|
||||
lit <<' _';
|
||||
lit_ <<' _';
|
||||
<h2 id="goal">Goal</h2>
|
||||
<p>
|
||||
The state of online indices of manual pages used to be a sad one. Existing
|
||||
|
|
@ -688,14 +700,7 @@ sub man_nav_ {
|
|||
'SELECT DISTINCT section FROM mans WHERE name =', \$man->{name}, 'ORDER BY section'
|
||||
)->@*;
|
||||
|
||||
my @lang = map $_->{lang}, tuwf->dbAlli(
|
||||
"SELECT DISTINCT substring(l.locale from '^[^.]+') AS lang
|
||||
FROM files f
|
||||
JOIN mans m ON m.id = f.man
|
||||
JOIN locales l ON l.id = f.locale
|
||||
WHERE m.name =", \$man->{name}, 'AND m.section =', \$man->{section}, "
|
||||
ORDER BY substring(l.locale from '^[^.]+') NULLS FIRST"
|
||||
)->@*;
|
||||
my $lang = man_languages $man->{name}, $man->{section};
|
||||
|
||||
nav_ sub {
|
||||
form_ action => '/sysredir/'.$url->mansect(), method => 'get',
|
||||
|
|
@ -736,11 +741,11 @@ sub man_nav_ {
|
|||
}
|
||||
}
|
||||
|
||||
if(@lang > 1) {
|
||||
if(@$lang > 1) {
|
||||
b_ 'Languages';
|
||||
p_ sub {
|
||||
(my $cur = $man->{locale}||'') =~ s/\..*//;
|
||||
for (@lang) {
|
||||
for (@$lang) {
|
||||
if(($_||'') eq $cur) {
|
||||
i_ $_ || 'default';
|
||||
} else {
|
||||
|
|
@ -796,7 +801,7 @@ sub man_page {
|
|||
if($url->{fmt} eq 'raw') {
|
||||
tuwf->resHeader('Content-Type', 'text/plain; charset=UTF-8');
|
||||
tuwf->resHeader('Content-Disposition', sprintf 'filename="%s.%s"', $man->{name}, $man->{section});
|
||||
lit $content->{content};
|
||||
lit_ $content->{content};
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -806,7 +811,7 @@ sub man_page {
|
|||
# This feature is a WIP and not advertised at the moment, anyway.
|
||||
tuwf->resHeader('Content-Type', 'text/plain; charset=UTF-8');
|
||||
tuwf->resHeader('Content-Disposition', sprintf 'filename="%s.%s.txt"', $man->{name}, $man->{section});
|
||||
lit $fmt;
|
||||
lit_ $fmt;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -823,34 +828,19 @@ sub man_page {
|
|||
qq{\n<a href="#head$c" id="head$c">$1</a>\n}
|
||||
}eg;
|
||||
|
||||
my $hasversions = tuwf->dbVali(
|
||||
'SELECT 1
|
||||
FROM files f
|
||||
JOIN mans m ON m.id = f.man
|
||||
JOIN locales l ON l.id = f.locale
|
||||
WHERE m.name =', \$man->{name}, 'AND m.section =', \$man->{section}, '
|
||||
AND l.locale =', \$man->{locale}, '
|
||||
AND f.shorthash <> ', \$man->{shorthash}, '
|
||||
LIMIT 1'
|
||||
);
|
||||
my @htmllang = $man->{locale} =~ /^([a-z]{2,3})(?:_([A-Z]{2}))?(?:$|@|\.)/ ? (lang => $1.($2?"-$2":'')) : ();
|
||||
|
||||
framework_ title => $man->{name}, mainclass => 'manpage', sub {
|
||||
man_nav_ $man, $url, \@toc, \@htmllang;
|
||||
div_ id => 'manbuttons', sub {
|
||||
h1_ $man->{name};
|
||||
ul_ 'data-hash' => $content->{hash},
|
||||
'data-name' => $man->{name},
|
||||
'data-section' => $man->{section},
|
||||
'data-locale' => $man->{locale}||'',
|
||||
'data-hasversions' => $hasversions?1:0,
|
||||
sub {
|
||||
ul_ sub {
|
||||
li_ sub { a_ href => $url->set(fmt => 'raw'), 'source' };
|
||||
li_ sub { a_ href => $url->set(system => sysbyid->{$man->{system}}{short}, package => undef, shorthash => shorthash_to_hex $man->{shorthash}), 'permalink' };
|
||||
li_ sub { a_ href => "/ver.".shorthash_to_hex($man->{shorthash}).($man->{locale}?".$man->{locale}":'')."/$man->{name}.$man->{section}", 'versions' };
|
||||
li_ sub { a_ href => "/loc/$content->{hash}", 'locations' };
|
||||
}
|
||||
};
|
||||
div_ id => 'manres', class => 'hidden', '';
|
||||
pre_ @htmllang, sub { lit_ $fmt };
|
||||
};
|
||||
}
|
||||
|
|
@ -1129,11 +1119,11 @@ TUWF::get qr{/loc/([a-fA-F0-9]{40})}, sub {
|
|||
td_ 'Package';
|
||||
td_ 'Path';
|
||||
}};
|
||||
my $lastrel = '';
|
||||
tr_ sub {
|
||||
my $sys = sysbyid->{$_->{system}};
|
||||
td_ sub {
|
||||
txt_ $sys->{release};
|
||||
} if $sys->{release};
|
||||
td_ $lastrel eq $sys->{release} ? '' : $sys->{release} if $sys->{release};
|
||||
$lastrel = $sys->{release};
|
||||
td_ sub {
|
||||
a_ href => "/pkg/$sys->{short}/$_->{package}/$_->{version}", $_->{package}.'-'.$_->{version};
|
||||
};
|
||||
|
|
@ -1146,100 +1136,79 @@ TUWF::get qr{/loc/([a-fA-F0-9]{40})}, sub {
|
|||
};
|
||||
|
||||
|
||||
TUWF::get '/json/tree.json' => sub {
|
||||
my $f = tuwf->validate(get =>
|
||||
name => { default => '', maxlength => 256 },
|
||||
section => { default => '', maxlength => 32 },
|
||||
locale => { default => sub{$_[0]}, maxlength => 32 },
|
||||
cur => { default => '', regex => qr/^[a-fA-F0-9]{40}$/ },
|
||||
hash => { default => '', regex => qr/^[a-fA-F0-9]{40}$/ },
|
||||
)->data;
|
||||
return tuwf->resNotFound() if !$f->{hash} && !($f->{section} && $f->{name});
|
||||
# /ver[.$shorthash][.$lang]/$name.$section
|
||||
TUWF::get qr{/ver(?:\.([a-fA-F0-9]{8}))?(?:\.([^/]+))?/([^/]+)\.([0-9a-zA-Z])}, sub {
|
||||
my($shorthash, $lang, $name, $sect) = tuwf->captures(1,2,3,4);
|
||||
$shorthash = $shorthash ? shorthash_to_int $shorthash : -1;
|
||||
($lang ||= '') =~ s/\..*//;
|
||||
|
||||
my $l = tuwf->dbAlli("
|
||||
SELECT p.system, p.name AS package, v.version, v.released, v.id AS verid, m.name, m.section, f.filename, f.shorthash, l.locale
|
||||
my $l = tuwf->dbAlli('
|
||||
SELECT p.system, p.name AS package, v.version, f.shorthash
|
||||
FROM files f
|
||||
JOIN locales l ON l.id = f.locale
|
||||
JOIN mans m ON m.id = f.man
|
||||
JOIN package_versions v ON v.id = f.pkgver
|
||||
JOIN packages p ON p.id = v.package
|
||||
JOIN systems s ON s.id = p.system
|
||||
WHERE", sql_and(
|
||||
length $f->{hash} ? sql 'f.content = (SELECT id FROM contents WHERE hash = decode(', \$f->{hash}, ", 'hex'))" : (),
|
||||
length $f->{name} ? sql 'm.name =', \$f->{name} : (),
|
||||
length $f->{section} ? sql 'm.section =', \$f->{section} : (),
|
||||
defined $f->{locale} ? sql 'l.locale =', \$f->{locale} : (),
|
||||
), '
|
||||
ORDER BY s.name, s.id DESC, p.name, v.released DESC, m.name, l.locale, f.filename
|
||||
WHERE f.man = (SELECT id FROM mans WHERE name =', \$name, 'AND section =', \$sect, ')
|
||||
AND f.locale IN(SELECT id FROM locales WHERE locale', $lang ? ('ILIKE', \(escape_like($lang).'%')) : ("= ''"), ')
|
||||
ORDER BY p.system DESC, p.name, v.released DESC, f.shorthash
|
||||
');
|
||||
|
||||
# Convert the list into a tree
|
||||
my $cur = $f->{cur} ? shorthash_to_int substr $f->{cur}, 0, 8 : 0;
|
||||
my $tree = [];
|
||||
my($sys, $sysver, $pkg, $pkgver);
|
||||
for my $m (@$l) {
|
||||
my $sysname = sysbyid->{$m->{system}}{name};
|
||||
if(!$sys || $sysname ne $sys->{name}) {
|
||||
$sys = { name => $sysname, childs => [] };
|
||||
$sysver = undef;
|
||||
push @$tree, $sys;
|
||||
}
|
||||
my $langs = man_languages $name, $sect;
|
||||
|
||||
my $sysversion = sysbyid->{$m->{system}}{release} || '';
|
||||
if(!$sysver || $sysversion ne $sysver->{name}) {
|
||||
$sysver = { name => $sysversion, childs => [] };
|
||||
$pkg = undef;
|
||||
push @{$sys->{childs}}, $sysver;
|
||||
}
|
||||
my %sys;
|
||||
push $sys{ sysbyid->{$_->{system}}{name} }->@*, $_ for @$l;
|
||||
|
||||
if(!$pkg || $m->{package} ne $pkg->{name}) {
|
||||
$pkg = { name => $m->{package}, table => [] };
|
||||
$pkgver = undef;
|
||||
push @{$sysver->{childs}}, $pkg;
|
||||
}
|
||||
my $title = "Versions of $name($sect)".($lang ? " in locale $lang" : '');
|
||||
framework_ title => $title, mainclass => 'verpage', sub {
|
||||
h1_ $title;
|
||||
|
||||
push @{$pkg->{table}}, [
|
||||
$pkgver && $pkgver eq $m->{version} ? {name=>''} :
|
||||
{name => $m->{version}, href => "/pkg/".sysbyid->{$m->{system}}{short}."/$m->{package}/$m->{version}"},
|
||||
{ name => "$m->{name}($m->{section})",
|
||||
$f->{hash} || $cur == $m->{shorthash} ? ()
|
||||
: (href => sprintf('/%s/%s', $m->{name}, shorthash_to_hex $m->{shorthash}))
|
||||
},
|
||||
{ name => shorthash_to_hex($m->{shorthash}),
|
||||
$f->{hash} || $cur == $m->{shorthash} ? ()
|
||||
: (href => sprintf('/%s/%s', $m->{name}, shorthash_to_hex $m->{shorthash}))
|
||||
},
|
||||
{ name => $m->{filename} }
|
||||
];
|
||||
$pkgver = $m->{version};
|
||||
}
|
||||
|
||||
# Determine which elements to show/hide by default.
|
||||
# It might make more sense to do this in JS, but since I am utterly
|
||||
# incapable of writing maintainable JS I'm doing it here in order to keep the
|
||||
# JS stupid and simple.
|
||||
# TODO: Highlight systems/packages where the 'current' man page is?
|
||||
for my $sys (@$tree) {
|
||||
$sys->{expand} = 1 if $sys->{childs}[0]{name}; # Expand all systems that have named versions
|
||||
$sys->{expand} = 1 if $f->{hash}; # Expand everything on 'location'
|
||||
|
||||
my $i = 0;
|
||||
for my $sysver (@{$sys->{childs}}) {
|
||||
$i++;
|
||||
$sysver->{expand} = 1 if !$sysver->{name}; # Expand unnamed versions (since you can't click them)
|
||||
$sysver->{expand} = 1 if $f->{hash}; # Expand everything on 'location'
|
||||
$sysver->{hide} = 1 if $i > 3 && @{$sys->{childs}} > 5; # Show only the first 3 versions
|
||||
|
||||
for my $pkg (@{$sysver->{childs}}) {
|
||||
$pkg->{expand} = 1 if @{$sysver->{childs}} <= 3; # Expand everything if there's not too many things to expand
|
||||
$pkg->{expand} = 1 if $f->{hash}; # Expand everything on 'location'
|
||||
|
||||
# TODO: Show/Hide duplicate hashes?
|
||||
}
|
||||
p_ sub {
|
||||
txt_ 'Available languages: ';
|
||||
for (0..$#{$langs}) {
|
||||
txt_ ', ' if $_ > 0;
|
||||
if(($langs->[$_]||'') eq $lang) {
|
||||
i_ $langs->[$_] || 'default';
|
||||
} else {
|
||||
a_ href => '/ver'.($langs->[$_]?".$langs->[$_]":'')."/$name.$sect", $langs->[$_] || 'default';
|
||||
}
|
||||
}
|
||||
txt_ '.';
|
||||
} if @$langs > 1;
|
||||
|
||||
tuwf->resJSON($tree);
|
||||
p_ sub {
|
||||
txt_ 'System index: ';
|
||||
my @sys = sort keys %sys;
|
||||
for (0..$#sys) {
|
||||
txt_ ', ' if $_ > 0;
|
||||
a_ href => "#$sys[$_]", $sys[$_];
|
||||
}
|
||||
txt_ '.';
|
||||
} if keys %sys > 1;
|
||||
|
||||
for my $sysname (sort keys %sys) {
|
||||
h2_ sub { a_ href => "#$sysname", id => "$sysname", $sysname };
|
||||
table_ sub {
|
||||
thead_ sub { tr_ sub {
|
||||
td_ 'Release' if sysbyid->{$sys{$sysname}[0]{system}}{release};
|
||||
td_ 'Package';
|
||||
td_ 'Hash';
|
||||
}};
|
||||
my $lastrel = '';
|
||||
tr_ sub {
|
||||
my $sys = sysbyid->{$_->{system}};
|
||||
td_ $lastrel eq $sys->{release} ? '' : $sys->{release} if $sys->{release};
|
||||
$lastrel = $sys->{release};
|
||||
td_ sub {
|
||||
a_ href => "/pkg/$sys->{short}/$_->{package}/$_->{version}", $_->{package}.'-'.$_->{version};
|
||||
};
|
||||
td_ class => 'sh', sub {
|
||||
my $hex = shorthash_to_hex $_->{shorthash};
|
||||
txt_ $hex if $_->{shorthash} == $shorthash;
|
||||
a_ href => "/man.$hex/$sys->{short}/$name.$sect", $hex if $_->{shorthash} != $shorthash;
|
||||
};
|
||||
} for $sys{$sysname}->@*;
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
38
www/man.css
38
www/man.css
|
|
@ -4,7 +4,7 @@ body { margin: 10px auto 50px auto; max-width: 1100px; border-collapse: separate
|
|||
h1 { font-size: 24px; font-weight: normal }
|
||||
h2 { font-size: 21px; margin-top: 35px; margin-bottom: 7px; font-weight: normal; border-bottom: 1px solid #ccc }
|
||||
h3 { font-size: 18px; margin-top: 20px; margin-bottom: 5px; font-weight: normal }
|
||||
a { color: #048; text-decoration: none }
|
||||
a { color: #048; text-decoration: none; font-family: inherit }
|
||||
a:hover { text-decoration: underline; color: #48B;}
|
||||
p { margin-bottom: 15px }
|
||||
dl { margin-bottom: 15px }
|
||||
|
|
@ -50,32 +50,11 @@ main.thin { max-width: 700px; margin: 0 auto }
|
|||
.pkgpage section:first-child { border-right: 1px dashed #468; padding: 0 10px }
|
||||
.pkgpage section:last-child { padding: 0 10px }
|
||||
|
||||
|
||||
#manbuttons h1 { display: inline; margin: 0 20px 0 0; vertical-align: middle }
|
||||
#manbuttons ul { list-style-type: none; display: inline-block }
|
||||
#manbuttons li { display: inline-block }
|
||||
#manbuttons li a, #manbuttons li i { display: inline-block; outline: none; margin: 0 10px 0 0; padding: 5px 7px 8px 7px; text-decoration: none; border-top-left-radius: 7px 5px; border-top-left-radius: 7px 5px }
|
||||
#manbuttons li i { font-style: normal; text-decoration: line-through; color: #aaa }
|
||||
#manbuttons li a:hover, #manbuttons li a.active { background: #f0f8ff }
|
||||
|
||||
#closebtn { float: right; margin: -5px 0 -20px 0; text-decoration: none; outline: none; color: #036; font-weight: bold }
|
||||
|
||||
#manres { margin: 0 0 10px 0; width: 70%; padding: 10px; box-sizing: border-box; background: #f0f8ff; border-radius: 10px; border-left: 1px dashed #333; border-right: 1px dashed #333 }
|
||||
#manres i { color: #aaa; font-size: 13px; margin-left: 7px }
|
||||
#manres ul { list-style-type: none; margin-bottom: 0 }
|
||||
#manres ul a { outline: none; text-decoration: none }
|
||||
#manres ul .oldver a { color: #aaa; font-size: 13px }
|
||||
#manres div > ul { margin-top: 5px } /* System names */
|
||||
#manres div > ul > li > a { color: #036; font-weight: bold } /* System names */
|
||||
#manres div > ul > li > ul { margin-left: 15px } /* System versions */
|
||||
#manres div > ul > li > ul > li > a { color: #000 } /* System versions */
|
||||
#manres div > ul > li > ul > li > ul { margin-left: 15px } /* Package names */
|
||||
#manres div > ul > li > ul > li > ul > li > a { color: #000 } /* Package names */
|
||||
#manres table { margin: 10px 0; border-collapse: collapse; }
|
||||
#manres td { padding: 1px 5px; font-size: 12px; }
|
||||
#manres td + td { border-left: 1px solid #ccc }
|
||||
#manres table { margin: 2px 10px; }
|
||||
#manres table tr td:nth-child(1) { min-width: 80px }
|
||||
#manbuttons li a { display: inline-block; outline: none; margin: 0 10px 0 0; padding: 5px 7px 8px 7px; text-decoration: none; border-top-left-radius: 7px 5px; border-top-left-radius: 7px 5px }
|
||||
#manbuttons li a:hover { background: #f0f8ff }
|
||||
|
||||
.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 }
|
||||
|
|
@ -93,16 +72,11 @@ main.thin { max-width: 700px; margin: 0 auto }
|
|||
.locpage tr td { padding: 2px 7px }
|
||||
.locpage tbody tr td:last-child { font-size: 12px }
|
||||
|
||||
.verpage p { margin-top: 15px }
|
||||
.verpage tr td { padding: 2px 7px }
|
||||
.verpage tbody tr td:last-child { font-family: "Lucida Console", monospace }
|
||||
|
||||
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 }
|
||||
|
||||
#ds_box { position: absolute; top: 0; border: 1px solid $border$; border-top: none; background: #f0f8ff; cursor: pointer; z-index: 2 }
|
||||
#ds_box b { padding: 2px 0 0 10px; font-size: 12px; }
|
||||
#ds_box tr.selected { background: #fff; }
|
||||
#ds_box table { width: 100% }
|
||||
#ds_box td { border: 0; padding: 1px 5px }
|
||||
#ds_box i { padding-left: 5px; color: #aaa; font-style: normal }
|
||||
|
||||
|
|
|
|||
246
www/man.js
246
www/man.js
|
|
@ -1,246 +0,0 @@
|
|||
/* The following functions are part of a minimal JS library I wrote for VNDB.org */
|
||||
|
||||
var expanded_icon = '▾';
|
||||
var collapsed_icon = '▸';
|
||||
|
||||
var http_request = false;
|
||||
function ajax(url, func, async) {
|
||||
if(!async && http_request)
|
||||
http_request.abort();
|
||||
var req = (window.ActiveXObject) ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
|
||||
if(req == null)
|
||||
return alert("Your browser does not support the functionality this website requires.");
|
||||
if(!async)
|
||||
http_request = req;
|
||||
req.onreadystatechange = function() {
|
||||
if(!req || req.readyState != 4 || !req.responseText)
|
||||
return;
|
||||
if(req.status != 200)
|
||||
return alert('Whoops, error! :(');
|
||||
func(req);
|
||||
};
|
||||
url += (url.indexOf('?')>=0 ? ';' : '?')+(Math.floor(Math.random()*999)+1);
|
||||
req.open('GET', url, true);
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
function byId(n) {
|
||||
return document.getElementById(n)
|
||||
}
|
||||
function byName(){
|
||||
var d = arguments.length > 1 ? arguments[0] : document;
|
||||
var n = arguments.length > 1 ? arguments[1] : arguments[0];
|
||||
return d.getElementsByTagName(n);
|
||||
}
|
||||
function byClass() { // [class], [parent, class], [tagname, class], [parent, tagname, class]
|
||||
var par = typeof arguments[0] == 'object' ? arguments[0] : document;
|
||||
var t = arguments.length == 2 && typeof arguments[0] == 'string' ? arguments[0] : arguments.length == 3 ? arguments[1] : '*';
|
||||
var c = arguments[arguments.length-1];
|
||||
var l = byName(par, t);
|
||||
var ret = [];
|
||||
for(var i=0; i<l.length; i++)
|
||||
if(hasClass(l[i], c))
|
||||
ret[ret.length] = l[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* wrapper around DOM element creation
|
||||
* tag('string') -> createTextNode
|
||||
* tag('tagname', tag(), 'string', ..) -> createElement(), appendChild(), ..
|
||||
* tag('tagname', { class: 'meh', title: 'Title' }) -> createElement(), setAttribute()..
|
||||
* tag('tagname', { <attributes> }, <elements>) -> create, setattr, append */
|
||||
function tag() {
|
||||
if(arguments.length == 1)
|
||||
return typeof arguments[0] != 'object' ? document.createTextNode(arguments[0]) : arguments[0];
|
||||
var el = typeof document.createElementNS != 'undefined'
|
||||
? document.createElementNS('http://www.w3.org/1999/xhtml', arguments[0])
|
||||
: document.createElement(arguments[0]);
|
||||
for(var i=1; i<arguments.length; i++) {
|
||||
if(arguments[i] == null)
|
||||
continue;
|
||||
if(typeof arguments[i] == 'object' && !arguments[i].appendChild) {
|
||||
for(attr in arguments[i]) {
|
||||
if(attr == 'style')
|
||||
el.setAttribute(attr, arguments[i][attr]);
|
||||
else
|
||||
el[ attr == 'class' ? 'className' : attr == 'for' ? 'htmlFor' : attr ] = arguments[i][attr];
|
||||
}
|
||||
} else
|
||||
el.appendChild(tag(arguments[i]));
|
||||
}
|
||||
return el;
|
||||
}
|
||||
function getText(obj) {
|
||||
return obj.textContent || obj.innerText || '';
|
||||
}
|
||||
function setText(obj, txt) {
|
||||
if(obj.textContent != null)
|
||||
obj.textContent = txt;
|
||||
else
|
||||
obj.innerText = txt;
|
||||
}
|
||||
|
||||
function listClass(obj) {
|
||||
var n = obj.className;
|
||||
if(!n)
|
||||
return [];
|
||||
return n.split(/ /);
|
||||
}
|
||||
function hasClass(obj, c) {
|
||||
var l = listClass(obj);
|
||||
for(var i=0; i<l.length; i++)
|
||||
if(l[i] == c)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
function setClass(obj, c, set) {
|
||||
var l = listClass(obj);
|
||||
var n = [];
|
||||
if(set) {
|
||||
n = l;
|
||||
if(!hasClass(obj, c))
|
||||
n[n.length] = c;
|
||||
} else {
|
||||
for(var i=0; i<l.length; i++)
|
||||
if(l[i] != c)
|
||||
n[n.length] = l[i];
|
||||
}
|
||||
obj.className = n.join(' ');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The tabs on man pages
|
||||
(function(){
|
||||
var ul = byId('manbuttons');
|
||||
if(!ul)
|
||||
return;
|
||||
var res = byId('manres');
|
||||
ul = byName(ul, 'ul')[0];
|
||||
|
||||
|
||||
var table = function(tbl, prop) {
|
||||
var t = tag('table', prop);
|
||||
for(row in tbl) {
|
||||
row = tbl[row];
|
||||
var r = tag('tr', {});
|
||||
for(col in row) {
|
||||
col = row[col];
|
||||
r.appendChild(tag('td',
|
||||
col.bold ? tag('b', col.name) :
|
||||
col.href ? tag('a', {href:col.href}, col.name) : col.name
|
||||
));
|
||||
}
|
||||
t.appendChild(r);
|
||||
}
|
||||
return t;
|
||||
};
|
||||
|
||||
var treeoldver = function() {
|
||||
var lnk = this;
|
||||
var ul = lnk;
|
||||
var show = !lnk['data-shown'];
|
||||
lnk['data-shown'] = show;
|
||||
|
||||
while(ul.nodeName.toLowerCase() != 'ul')
|
||||
ul = ul.parentNode;
|
||||
var l = ul.childNodes;
|
||||
for(var i=0; i<l.length; i++) {
|
||||
if(l[i].nodeName.toLowerCase() == 'li' && l[i]['data-oldver'])
|
||||
setClass(l[i], 'hidden', !show);
|
||||
}
|
||||
|
||||
setText(lnk, (show ? '- ' : '+ ')+lnk['data-hidnum']+' older versions');
|
||||
return false;
|
||||
};
|
||||
|
||||
var treeexpand = function() {
|
||||
var sub = byName(this.parentNode, 'ul')[0] || byName(this.parentNode, 'table')[0];
|
||||
var exp = hasClass(sub, 'hidden');
|
||||
setClass(sub, 'hidden', !exp);
|
||||
setText(this, getText(this).replace(/^[^ ]+/, exp ? expanded_icon : collapsed_icon));
|
||||
return false;
|
||||
};
|
||||
|
||||
var treeitem = function(n) {
|
||||
var icon = n.name ? (n.expand ? expanded_icon : collapsed_icon)+' ' : '';
|
||||
return tag('li', n.hide ? {'class':'hidden', 'data-oldver':true} : {},
|
||||
tag('a', {href:'#', onclick: treeexpand}, icon+n.name),
|
||||
n.i ? tag('i', n.i) : null,
|
||||
n.childs ? treelist(n.childs, n.expand ? {} : {'class':'hidden'}) : null,
|
||||
n.table ? table(n.table, n.expand ? {} : {'class':'hidden'}) : null
|
||||
);
|
||||
};
|
||||
|
||||
var treelist = function(lst, prop) {
|
||||
var ul = tag('ul', prop);
|
||||
var hidden = 0;
|
||||
|
||||
for(i in lst) {
|
||||
var n = lst[i];
|
||||
if(n.hide)
|
||||
hidden++;
|
||||
ul.appendChild(treeitem(lst[i]));
|
||||
}
|
||||
|
||||
if(hidden > 0)
|
||||
ul.appendChild(tag('li', {'class':'oldver'},
|
||||
tag('a', {href:'#', onclick: treeoldver, 'data-hidnum':hidden}, '+ '+hidden+' older versions')
|
||||
));
|
||||
return ul;
|
||||
};
|
||||
|
||||
var clearactive = function() {
|
||||
setClass(res, 'hidden', true);
|
||||
var l = byName(ul, 'a');
|
||||
for(var i=0; i<l.length; i++) {
|
||||
setClass(l[i], 'active', false);
|
||||
if(l[i]['data-obj'])
|
||||
setClass(l[i]['data-obj'], 'hidden', true);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var loading = tag('div', {'class':'hidden'}, 'Loading...');
|
||||
|
||||
var buttonclick = function() {
|
||||
var btn = this;
|
||||
var isactive = hasClass(btn, 'active');
|
||||
clearactive();
|
||||
if(isactive)
|
||||
return false;
|
||||
|
||||
if(btn['data-obj']) {
|
||||
setClass(btn['data-obj'], 'hidden', false);
|
||||
} else {
|
||||
setClass(loading, 'hidden', false);
|
||||
ajax(btn['data-url'], function(r) {
|
||||
setClass(loading, 'hidden', true);
|
||||
r = JSON.parse(r.responseText);
|
||||
btn['data-obj'] = tag('div', tag('p', btn['data-p']), treelist(r, {}));
|
||||
res.appendChild(btn['data-obj']);
|
||||
});
|
||||
}
|
||||
setClass(btn, 'active', true);
|
||||
setClass(res, 'hidden', false);
|
||||
return false;
|
||||
};
|
||||
|
||||
res.insertBefore(tag('a', {id:'closebtn', href:'#', onclick: clearactive}, 'X'), res.firstChild);
|
||||
res.appendChild(loading);
|
||||
|
||||
(function(){
|
||||
var name = ul.getAttribute('data-name');
|
||||
var hash = ul.getAttribute('data-hash');
|
||||
var section = ul.getAttribute('data-section');
|
||||
var locale = ul.getAttribute('data-locale');
|
||||
|
||||
ul.insertBefore(tag('li', ul.getAttribute('data-hasversions') > 0
|
||||
? tag('a', {href:'#', onclick: buttonclick,
|
||||
'data-url': '/json/tree.json?name='+name+';section='+section+';locale='+locale+';cur='+hash,
|
||||
'data-p': 'Different versions of this manual page are available.'},
|
||||
'versions')
|
||||
: tag('i', 'versions')
|
||||
), ul.childNodes[ul.childNodes.length-1]);
|
||||
})();
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue