summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2020-01-08 09:07:26 +0100
committerYorhel <git@yorhel.nl>2020-01-08 09:07:26 +0100
commit788ff22a82cd16c5bc31f70a25118a99372bcb5f (patch)
tree5857f959c131ba8364940264757a18ee0dc6fb85 /lib
parent5b1e69fb1972b00a7e8c154d84a0885c2c4bf95f (diff)
v2rw: Convert tag link browser
Diffstat (limited to 'lib')
-rw-r--r--lib/VNDB/Handler/Tags.pm115
-rw-r--r--lib/VNWeb/HTML.pm2
-rw-r--r--lib/VNWeb/Prelude.pm8
-rw-r--r--lib/VNWeb/Tags/Links.pm144
4 files changed, 149 insertions, 120 deletions
diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm
index cbc7b293..9e771997 100644
--- a/lib/VNDB/Handler/Tags.pm
+++ b/lib/VNDB/Handler/Tags.pm
@@ -15,7 +15,6 @@ TUWF::register(
qr{g([1-9]\d*)/(add)}, \&tagedit,
qr{g/new}, \&tagedit,
qr{g/list}, \&taglist,
- qr{g/links}, \&taglinks,
qr{v([1-9]\d*)/tagmod}, \&vntagmod,
qr{u([1-9]\d*)/tags}, \&usertags,
qr{g}, \&tagindex,
@@ -380,120 +379,6 @@ sub taglist {
}
-sub taglinks {
- my $self = shift;
-
- my $f = $self->formValidate(
- { get => 'p', required => 0, default => 1, template => 'page' },
- { get => 'o', required => 0, default => 'd', enum => ['a', 'd'] },
- { get => 's', required => 0, default => 'date', enum => [qw|date tag|] },
- { get => 'v', required => 0, default => 0, template => 'id' },
- { get => 'u', required => 0, default => 0, template => 'id' },
- { get => 't', required => 0, default => 0, template => 'id' },
- );
- return $self->resNotFound if $f->{_err} || $f->{p} > 100;
-
- my($list, $np) = $self->dbTagLinks(
- what => 'details',
- results => 50,
- page => $f->{p},
- sort => $f->{s},
- reverse => $f->{o} eq 'd',
- $f->{v} ? (vid => $f->{v}) : (),
- $f->{u} ? (uid => $f->{u}) : (),
- $f->{t} ? (tag => $f->{t}) : (),
- );
-
- my $url = sub {
- my %f = ((map +($_,$f->{$_}), qw|s o v u t|), @_);
- my $qs = join ';', map $f{$_}?"$_=$f{$_}":(), keys %f;
- return '/g/links'.($qs?"?$qs":'')
- };
-
- $self->htmlHeader(noindex => 1, title => 'Tag link browser');
- div class => 'mainbox';
- h1 'Tag link browser';
-
- div class => 'warning';
- h2 'Spoiler warning';
- p 'This list displays the tag votes of individual users. Spoilery tags are not hidden, and may not even be correctly flagged as such.';
- end;
- br;
-
- if($f->{u} || $f->{t} || $f->{v}) {
- p 'Active filters:';
- ul;
- if($f->{u}) {
- my $o = $self->dbUserGet(uid => $f->{u})->[0];
- li;
- txt '['; a href => $url->(u=>0), 'remove'; txt '] ';
- txt 'User: ';
- VNWeb::HTML::user_($o);
- end;
- }
- if($f->{t}) {
- my $o = $self->dbTagGet(id => $f->{t})->[0];
- li;
- txt '['; a href => $url->(t=>0), 'remove'; txt '] ';
- txt 'Tag:'; txt ' ';
- a href => "/g$f->{t}", $o->{name}||'Unknown tag';
- end;
- }
- if($f->{v}) {
- my $o = $self->dbVNGet(id => $f->{v})->[0];
- li;
- txt '['; a href => $url->(v=>0), 'remove'; txt '] ';
- txt 'Visual novel:'; txt ' ';
- a href => "/v$f->{v}", $o->{title}||'Unknown VN';
- end;
- }
- end 'ul';
- }
- p 'Click the arrow beside a user, tag or VN to add it as a filter.' unless $f->{v} && $f->{u} && $f->{t};
- end 'div';
-
- $self->htmlBrowse(
- class => 'taglinks',
- options => $f,
- nextpage => $np,
- items => $list,
- pageurl => $url->(),
- sorturl => $url->(s=>0,o=>0),
- header => [
- [ 'Date', 'date' ],
- [ 'User' ],
- [ 'Rating' ],
- [ 'Tag', 'tag' ],
- [ 'Spoiler' ],
- [ 'Visual novel' ],
- ],
- row => sub {
- my($s, $n, $l) = @_;
- Tr;
- td class => 'tc1', fmtdate $l->{date};
- td class => 'tc2';
- a href => $url->(u=>$l->{uid}), class => 'setfil', '> ' if $l->{user_id} && !$f->{u};
- VNWeb::HTML::user_($l);
- end;
- td class => 'tc3'.($l->{ignore}?' ignored':'');
- tagscore $l->{vote};
- end;
- td class => 'tc4';
- a href => $url->(t=>$l->{tag}), class => 'setfil', '> ' if !$f->{t};
- a href => "/g$l->{tag}", $l->{name};
- end;
- td class => 'tc5', !defined $l->{spoiler} ? ' ' : fmtspoil $l->{spoiler};
- td class => 'tc6';
- a href => $url->(v=>$l->{vid}), class => 'setfil', '> ' if !$f->{v};
- a href => "/v$l->{vid}", shorten $l->{title}, 50;
- end;
- end;
- },
- );
- $self->htmlFooter;
-}
-
-
sub vntagmod {
my($self, $vid) = @_;
diff --git a/lib/VNWeb/HTML.pm b/lib/VNWeb/HTML.pm
index 1d6731c2..066cbde9 100644
--- a/lib/VNWeb/HTML.pm
+++ b/lib/VNWeb/HTML.pm
@@ -47,7 +47,7 @@ sub clearfloat_ { div_ class => 'clearfloat', '' }
sub debug_ {
return if !tuwf->debug;
# This provides a nice JSON browser in FF, not sure how other browsers render it.
- my $data = uri_escape(JSON::XS->new->canonical->encode($_[0]));
+ my $data = uri_escape(JSON::XS->new->canonical->allow_nonref->encode($_[0]));
a_ style => 'margin: 0 5px', title => 'Debug', href => 'data:application/json,'.$data, ' ⚙ ';
}
diff --git a/lib/VNWeb/Prelude.pm b/lib/VNWeb/Prelude.pm
index 64ef289c..3f5d5f67 100644
--- a/lib/VNWeb/Prelude.pm
+++ b/lib/VNWeb/Prelude.pm
@@ -8,13 +8,13 @@
# use Exporter 'import';
# use Time::HiRes 'time';
# use List::Util 'min', 'max', 'sum';
-# use POSIX 'ceil';
+# use POSIX 'ceil', 'floor';
#
# use VNDBUtil;
# use VNDB::BBCode;
# use VNDB::Types;
# use VNDB::Config;
-# use VNDB::Func 'fmtdate', 'fmtage', 'fmtvote', 'query_encode';
+# use VNDB::Func 'fmtdate', 'fmtage', 'fmtvote', 'fmtspoil', 'query_encode';
# use VNDB::ExtLinks;
# use VNWeb::Auth;
# use VNWeb::HTML;
@@ -52,13 +52,13 @@ sub import {
use Exporter 'import';
use Time::HiRes 'time';
use List::Util 'min', 'max', 'sum';
- use POSIX 'ceil';
+ use POSIX 'ceil', 'floor';
use VNDBUtil;
use VNDB::BBCode;
use VNDB::Types;
use VNDB::Config;
- use VNDB::Func 'fmtdate', 'fmtage', 'fmtvote', 'query_encode';
+ use VNDB::Func 'fmtdate', 'fmtage', 'fmtvote', 'fmtspoil', 'query_encode';
use VNDB::ExtLinks;
use VNWeb::Auth;
use VNWeb::HTML;
diff --git a/lib/VNWeb/Tags/Links.pm b/lib/VNWeb/Tags/Links.pm
new file mode 100644
index 00000000..81d8e128
--- /dev/null
+++ b/lib/VNWeb/Tags/Links.pm
@@ -0,0 +1,144 @@
+package VNWeb::Tags::Links;
+
+use VNWeb::Prelude;
+
+
+# XXX: This is ugly, both in code and UI. Not sure what to replace it with.
+sub tagscore_ {
+ my $s = shift;
+ div_ class => 'taglvl', style => sprintf('width: %.0fpx', ($s-floor($s))*10), ' ' if $s < 0 && $s-floor($s) > 0;
+ for(-3..3) {
+ if($_ < 0) {
+ if($s > 0 || floor($s) > $_) {
+ div_ class => "taglvl taglvl$_", ' ';
+ } elsif(floor($s) != $_) {
+ div_ class => "taglvl taglvl$_ taglvlsel", ' ';
+ } else {
+ div_ class => "taglvl taglvl$_ taglvlsel", style => sprintf('width: %.0fpx', 10-($s-$_)*10), ' ';
+ }
+ } elsif($_ > 0) {
+ if($s < 0 || ceil($s) < $_) {
+ div_ class => "taglvl taglvl$_", ' ';
+ } elsif(ceil($s) != $_) {
+ div_ class => "taglvl taglvl$_ taglvlsel", ' ';
+ } else {
+ div_ class => "taglvl taglvl$_ taglvlsel", style => sprintf('width: %.0fpx', 10-($_-$s)*10), ' ';
+ }
+ } else {
+ div_ class => "taglvl taglvl0", sprintf '%.1f', $s;
+ }
+ }
+ div_ class => 'taglvl', style => sprintf('width: %.0fpx', (ceil($s)-$s)*10), ' ' if $s > 0 && ceil($s)-$s > 0;
+}
+
+
+sub listing_ {
+ my($opt, $lst, $np, $url) = @_;
+
+ paginate_ $url, $opt->{p}, $np, 't';
+ div_ class => 'mainbox browse taglinks', sub {
+ table_ class => 'stripe', sub {
+ thead_ sub { tr_ sub {
+ td_ class => 'tc1', sub { txt_ 'Date'; sortable_ 'date', $opt, $url; debug_ $lst; };
+ td_ class => 'tc2', 'User';
+ td_ class => 'tc3', 'Rating';
+ td_ class => 'tc4', sub { txt_ 'Tag'; sortable_ 'tag', $opt, $url };
+ td_ class => 'tc5', 'Spoiler';
+ td_ class => 'tc6', 'Visual novel';
+ }};
+ tr_ sub {
+ my $i = $_;
+ td_ class => 'tc1', fmtdate $i->{date};
+ td_ class => 'tc2', sub {
+ a_ href => $url->(u => $i->{uid}, p=>undef), class => 'setfil', '> ' if !defined $opt->{u};
+ user_ $i;
+ };
+ td_ mkclass(tc3 => 1, ignored => $i->{ignored}), sub { tagscore_ $i->{vote} };
+ td_ class => 'tc4', sub {
+ a_ href => $url->(t => $i->{uid}, p=>undef), class => 'setfil', '> ' if !defined $opt->{t};
+ a_ href => "/g$i->{tag}", $i->{name};
+ };
+ td_ class => 'tc5', !defined $i->{spoiler} ? '' : fmtspoil $i->{spoiler};
+ td_ class => 'tc6', sub {
+ a_ href => $url->(v => $i->{vid}, p=>undef), class => 'setfil', '> ' if !defined $opt->{v};
+ a_ href => "/v$i->{vid}", shorten $i->{title}, 50;
+ };
+ } for @$lst;
+ };
+ };
+ paginate_ $url, $opt->{p}, $np, 'b';
+}
+
+
+TUWF::get qr{/g/links}, sub {
+ my $opt = tuwf->validate(get =>
+ p => { page => 1 },
+ o => { onerror => 'd', enum => ['a', 'd'] },
+ s => { onerror => 'date', enum => [qw|date tag|] },
+ v => { onerror => undef, id => 1 },
+ u => { onerror => undef, id => 1 },
+ t => { onerror => undef, id => 1 },
+ )->data;
+
+ my $where = sql_and
+ defined $opt->{v} ? sql('tv.vid =', \$opt->{v}) : (),
+ defined $opt->{u} ? sql('tv.uid =', \$opt->{u}) : (),
+ defined $opt->{t} ? sql('tv.tag =', \$opt->{t}) : ();
+
+ my $filt = defined $opt->{u} || defined $opt->{t} || defined $opt->{v};
+
+ my $count = $filt && tuwf->dbVali('SELECT COUNT(*) FROM tags_vn tv WHERE', $where);
+ my($lst, $np) = tuwf->dbPagei({ page => $opt->{p}, results => 50 }, '
+ SELECT tv.vid, tv.uid, tv.tag, tv.vote, tv.spoiler,', sql_totime('tv.date'), 'as date, tv.ignore, v.title,', sql_user(), ', t.name
+ FROM tags_vn tv
+ JOIN vn v ON v.id = tv.vid
+ JOIN users u ON u.id = tv.uid
+ JOIN tags t ON t.id = tv.tag
+ WHERE', $where, '
+ ORDER BY', { date => 'tv.date', tag => 't.name' }->{$opt->{s}}, { a => 'ASC', d => 'DESC' }->{$opt->{o}}
+ );
+ $np = [ $count, 50 ] if $count;
+
+ my sub url { '?'.query_encode %$opt, @_ }
+
+ framework_ title => 'Tag link browser', sub {
+ div_ class => 'mainbox', sub {
+ h1_ 'Tag link browser';
+ div_ class => 'warning', sub {
+ h2_ 'Spoiler warning';
+ p_ 'This list displays the tag votes of individual users. Spoilery tags are not hidden, and may not even be correctly flagged as such.';
+ };
+ br_;
+ if($filt) {
+ p_ 'Active filters:';
+ ul_ sub {
+ li_ sub {
+ txt_ '['; a_ href => url(u=>undef, p=>undef), 'remove'; txt_ '] ';
+ txt_ 'User: ';
+ user_ tuwf->dbRowi('SELECT', sql_user(), 'FROM users u WHERE id=', \$opt->{u});
+ } if defined $opt->{u};
+ li_ sub {
+ txt_ '['; a_ href => url(t=>undef, p=>undef), 'remove'; txt_ '] ';
+ txt_ 'Tag:'; txt_ ' ';
+ a_ href => "/g$opt->{t}", tuwf->dbVali('SELECT name FROM tags WHERE id=', \$opt->{t})||'Unknown tag';
+ } if defined $opt->{t};
+ li_ sub {
+ txt_ '['; a_ href => url(v=>undef, p=>undef), 'remove'; txt_ '] ';
+ txt_ 'Visual novel'; txt_ ' ';
+ a_ href => "/v$opt->{v}", tuwf->dbVali('SELECT title FROM vn WHERE id=', \$opt->{v})||'Unknown VN';
+ } if defined $opt->{v};
+ }
+ }
+ if($lst && @$lst) {
+ p_ 'Click the arrow before a user, tag or VN to add it as a filter.'
+ if !defined $opt->{u} && !defined $opt->{t} && !defined $opt->{v};
+ } else {
+ p_ 'No tag votes matching the requested filters.';
+ }
+ };
+
+ listing_ $opt, $lst, $np, \&url if $lst && @$lst;
+ };
+};
+
+1;