summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSpaceRanger <space.ranger.vn@gmail.com>2012-07-13 19:06:36 +0200
committerYorhel <git@yorhel.nl>2012-07-13 19:06:36 +0200
commite649964b5b74bf1bdc44be9591cff45119aa3096 (patch)
treed5242f9843d65648ba410579497af88ecf8aa008 /lib
parentb017974cc80c2e3775fd52631854dc92a9aeab93 (diff)
Various improvements with the releases table
Diffstat (limited to 'lib')
-rw-r--r--lib/VNDB/DB/Releases.pm14
-rw-r--r--lib/VNDB/Handler/VNPage.pm360
2 files changed, 264 insertions, 110 deletions
diff --git a/lib/VNDB/DB/Releases.pm b/lib/VNDB/DB/Releases.pm
index 8bc9f6b3..f8271031 100644
--- a/lib/VNDB/DB/Releases.pm
+++ b/lib/VNDB/DB/Releases.pm
@@ -81,10 +81,16 @@ sub dbReleaseGet {
);
my $order = sprintf {
- title => 'rr.title %s',
- minage => 'rr.minage %s',
- released => 'rr.released %s, rr.title %1$s',
- }->{ $o{sort}||'released' }, $o{reverse} ? 'DESC' : 'ASC';
+ title => 'rr.title %s, rr.released %1$s',
+ type => 'rr.patch %s, rr.type %1$s, rr.released %1$s, rr.title %1$s',
+ publication => 'rr.doujin %s, rr.freeware %1$s, rr.patch %1$s, rr.released %1$s, rr.title %1$s',
+ resolution => 'rr.resolution %s, rr.patch %2$s, rr.released %1$s, rr.title %1$s',
+ voiced => 'rr.voiced %s, rr.patch %2$s, rr.released %1$s, rr.title %1$s',
+ ani_ero => 'rr.ani_story %s, rr.ani_ero %1$s, rr.patch %2$s, rr.released %1$s, rr.title %1$s',
+ released => 'rr.released %s, rr.title %1$s',
+ minage => 'rr.minage %s, rr.released %1$s, rr.title %1$s',
+ notes => 'rr.notes %s, rr.released %1$s, rr.title %1$s',
+ }->{ $o{sort}||'released' }, $o{reverse} ? 'DESC' : 'ASC', !$o{reverse} ? 'DESC' : 'ASC';
my($r, $np) = $self->dbPage(\%o, q|
SELECT !s
diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm
index f1b4376d..748aeb4d 100644
--- a/lib/VNDB/Handler/VNPage.pm
+++ b/lib/VNDB/Handler/VNPage.pm
@@ -56,6 +56,66 @@ sub releases {
$self->htmlMainTabs('v', $v, 'releases');
+ # the order of buttons and columns
+ my @columb_list = ( 'type',
+ 'languages',
+ 'publication',
+ 'platforms',
+ 'media',
+ 'resolution',
+ 'voiced',
+ 'ani_ero',
+ 'released',
+ 'minage',
+ 'notes');
+
+ # All data specific to the individual columns
+ my %c = (
+ 'title' => { column_string => '_relinfo_title',
+ },
+ 'type' => { button_string => '_relinfo_type',
+ },
+ 'languages' => { button_string => '_relinfo_lang',
+ unsortable => 'true',
+ },
+ 'publication' => { column_string => '_relinfo_publication',
+ column_width => 'max-width: 70px',
+ button_string => '_relinfo_publication',
+ },
+ 'platforms' => { button_string => '_redit_form_platforms',
+ unsortable => 'true',
+ },
+ 'media' => { column_string => '_redit_form_media',
+ button_string => '_redit_form_media',
+ unsortable => 'true',
+ },
+ 'resolution' => { column_string => '_relinfo_resolution',
+ button_string => '_relinfo_resolution',
+ na_for_patch => '1',
+ },
+ 'voiced' => { column_string => '_relinfo_voiced',
+ column_width => 'max-width: 70px',
+ button_string => '_relinfo_voiced',
+ na_for_patch => '1',
+ },
+ 'ani_ero' => { column_string => '_relinfo_ani',
+ column_width => 'max-width: 110px',
+ button_string => '_relinfo_ani',
+ na_for_patch => '1',
+ },
+ 'released' => { column_string => '_relinfo_released',
+ button_string => '_relinfo_released',
+ },
+ 'minage' => { button_string => '_relinfo_minage',
+ },
+ 'notes' => { column_string => '_redit_form_notes',
+ column_width => 'max-width: 400px',
+ button_string => '_redit_form_notes',
+ },
+ 'legend' => { unsortable => 'true',
+ },
+ );
+
my $f = $self->formValidate(
{ get => 'typ', required => 0, default => '1', enum => [ '0', '1' ] }, # type
{ get => 'lan', required => 0, default => '1', enum => [ '0', '1' ] }, # language
@@ -68,42 +128,38 @@ sub releases {
{ get => 'rel', required => 0, default => '1', enum => [ '0', '1' ] }, # released
{ get => 'min', required => 0, default => '1', enum => [ '0', '1' ] }, # min age
{ get => 'not', required => 0, default => '1', enum => [ '0', '1' ] }, # notes
- { get => 'rwr', required => 0, default => '0', enum => [ '0', '1' ] }, # restrict column width
+ { get => 'cw', required => 0, default => '0', enum => [ '0', '1' ] }, # restrict column width
+ { get => 'o', required => 0, default => '0', enum => [ '0', '1' ] }, # sort order
+ { get => 's', required => 0, default => 'released', enum => [ grep !$c{$_}{unsortable}, keys %c ]}, # sort by column
+ { get => 'os', required => 0, default => 'all', enum => [ 'all', @{$self->{platforms}} ] }, # filter by os
+ { get => 'lang', required => 0, default => 'all', enum => [ 'all', @{$self->{languages}} ] }, # filter by language
);
return $self->resNotFound if $f->{_err};
- # the order of buttons and columns
- my @columb_list = ( 'type',
- 'languages',
- 'publication',
- 'platforms',
- 'media',
- 'resolution',
- 'voiced',
- 'ani_ero',
- 'released',
- 'minage',
- 'notes');
- # button strings
- my %button_strings = ( 'typ' => '_relinfo_type',
- 'lan' => '_relinfo_lang',
- 'pub' => '_relinfo_publication',
- 'pla' => '_redit_form_platforms',
- 'med' => '_redit_form_media',
- 'res' => '_relinfo_resolution',
- 'voi' => '_relinfo_voiced',
- 'ani' => '_relinfo_ani',
- 'rel' => '_relinfo_released',
- 'min' => '_relinfo_minage',
- 'not' => '_redit_form_notes' );
-
# Get the releases
# Setup $what_string to use only the bare minimum to reduce database load
my $what_string = '';
- $what_string .= ' extended' if $f->{typ}||$f->{rel}||$f->{voi}||$f->{ani}||$f->{not};
+ $what_string .= ' extended' if $f->{pub}||$f->{res}||$f->{voi}||$f->{ani}||$f->{not};
$what_string .= ' platforms' if $f->{pla};
$what_string .= ' media' if $f->{med};
- my $r = $self->dbReleaseGet(vid => $vid, what => $what_string);
+ my $r = $self->dbReleaseGet(vid => $vid, what => $what_string, sort => $f->{s}, reverse => $f->{o});
+
+ # url generator
+ my $url = sub {
+ my($type, $new_val, $new_sort_type) = @_;
+
+ # create a link, which includes all settings in $f
+ my $generated_url = "/v$vid/releases?";
+ foreach ( keys %$f ) {
+ if ($_ eq 's' && $type eq 'o' ) {
+ # changing o changes s as well
+ $generated_url .= ';s=' . $new_sort_type;
+ next;
+ }
+ $generated_url .= ';' . $_ . '='.($type eq $_ ? $new_val : $f->{$_});
+ }
+ return $generated_url;
+ };
div class => 'mainbox releases_compare';
h1 $title;
@@ -111,30 +167,80 @@ sub releases {
if(!@$r) {
# No releases to write in table
# End before drawing anything in the table
- td mt '_vnpage_rel_none' if (!@$r) ;
+ td mt '_vnpage_rel_none';
} else {
- # url generator
- my $url = sub {
- my($type) = @_;
+ # change all column hide/show status to $new_val while keeping the rest of the settings untouched
+ my $all_url = sub {
+ my($new_val) = @_;
- # create a link, which includes all settings in $f
my $generated_url = "/v$vid/releases?";
- foreach ( keys %$f ) {
- $generated_url .= ';' . $_ . '='.($type eq $_ ? $f->{$_} ? 0 : 1 : $f->{$_});
+ foreach my $key ( keys %$f ) {
+ # Note all columns have a length of 3 while non-columns have lengths different from 3
+ $generated_url .= ';' . $key . '='. (length($key) == 3 ? $new_val : $f->{$key});
}
return $generated_url;
};
+ my $get_lang_plat_list = sub {
+ my($type) = @_;
+
+ my @return_array = ();
+ for my $rel (@$r) {
+ for my $element (@{$rel->{$type}}) {
+ push(@return_array, $element) if not (grep $_ eq $element, @return_array);
+ }
+ }
+ return sort(@return_array); # sort to make order consistent
+ };
+
+ my $all_selected = sub {
+ my($value) = @_;
+
+ for (@columb_list) {
+ if (!$f->{substr($_,0,3)} != !$value) {
+ return 0;
+ }
+ }
+ return 1;
+ };
+
+ # Language and platform drawing code is almost identical. Skip writing it twice
+ my $plat_lang_draw = sub {
+ my($row, $option, $lang) = @_;
+
+ if (!$f->{substr($row, 0, 3)}) {
+ # Column is hidden
+ # Do not display row of platforms/flags as they aren't read from the database
+ # Set filter to all as it makes no sense to try to filter by hidden and potientially unread data
+ $f->{$option} = 'all';
+ return;
+ }
+
+ p class => 'browseopts';
+ foreach ( 'all', $get_lang_plat_list->($row)) {
+ a href => $url->($option, $_), $_ eq $f->{$option} ? (class => 'optselected') : ();
+ $_ eq 'all' ? txt mt '_all' :
+ cssicon "$lang $_", mt '_' . substr($row, 0, 4) . '_' . $_;
+ end 'a';
+ };
+ end 'p';
+ };
+
p class => 'browseopts';
foreach ( @columb_list ) {
my $short_name = substr($_, 0, 3);
- a href => $url->($short_name), 0 == $f->{$short_name} ? (class => 'optselected') : (), mt $button_strings{$short_name};
+ a href => $url->($short_name, $f->{$short_name} ? 0 : 1), $f->{$short_name} ? (class => 'optselected') : (), mt $c{$_}{button_string};
};
end;
p class => 'browseopts';
- a href => $url->('rwr'), 0 == $f->{rwr} ? (class => 'optselected') : (), mt '_vnpage_restrict_column_width';
+ a href => $all_url->(1), $all_selected->(1) ? (class => 'optselected') : (), mt '_all_on';
+ a href => $all_url->(0), $all_selected->(0) ? (class => 'optselected') : (), mt '_all_off';
+ a href => $url->('cw', $f->{cw} ? 0 : 1), $f->{cw} ? (class => 'optselected') : (), mt '_vnpage_restrict_column_width';
end;
+
+ $plat_lang_draw->('platforms', 'os', '' );
+ $plat_lang_draw->('languages', 'lang', 'lang');
}
end 'div';
if(!@$r) {
@@ -142,13 +248,25 @@ sub releases {
return;
}
+ # Remove all releases which fails to meet the platform and language filter settings
+ my $counter = 0;
+ while ($counter <= $#$r) {
+ my $rel = @$r[$counter];
+ if (($f->{os} eq 'all' || $f->{os} ~~ $rel->{platforms}) &&
+ ($f->{lang} eq 'all' || $f->{lang} ~~ $rel->{languages}) ){
+ $counter++;
+ } else {
+ splice @$r, $counter, 1;
+ }
+ };
+
div class => 'mainbox releases_compare';
table;
- my $counter = 0;
+ $counter = 0;
my @column_types = ( 'title' );
foreach ( @columb_list ) {
- next if not $f->{substr($_, 0, 3)}; # skip columns ubselected in f
+ next if not $f->{substr($_, 0, 3)}; # skip columns unselected in f
if (_column_is_in_use($r, $_)){
push(@column_types, $_);
$counter++;
@@ -162,70 +280,90 @@ sub releases {
}
# Draw the top/key row based on @column_types
- # init %height at the same time as it needs to be set for each columbtype anyway
- my %height = ();
- Tr;
- foreach my $column_type (@column_types) {
- $height{$column_type} = 0;
- given ($column_type) {
- when ('title') { td class => 'key', mt '_relinfo_title'; }
- when ('type') { td class => 'key'; end 'td'; }
- when ('languages') { td class => 'key'; end 'td'; }
- when ('publication'){ td class => 'key', mt '_relinfo_publication'; }
- when ('platforms') { td class => 'key'; end 'td'; }
- when ('media') { td class => 'key', mt '_redit_form_media'; }
- when ('resolution') { td class => 'key', mt '_relinfo_resolution'; }
- when ('voiced') { td class => 'key', mt '_relinfo_voiced'; }
- when ('ani_ero') { td class => 'key', mt '_relinfo_ani'; }
- when ('released') { td class => 'key', mt '_relinfo_released'; }
- when ('minage') { td class => 'key'; end 'td'; }
- when ('notes') { td class => 'key', mt '_redit_form_notes'; }
- when ('legend') { td class => 'key'; end 'td'; }
+ thead;
+ Tr;
+ foreach my $column_type (@column_types) {
+ td class => 'key';
+ txt mt $c{$column_type}{column_string} if $c{$column_type}{column_string};
+ if (!$c{$column_type}{unsortable}) {
+ for(0..1) {
+ # draw the assending/decending arrows
+ # draw it in a a container with a link unless it is the already selected one
+ my $make_link = !($f->{s} eq $column_type && $f->{o} == $_);
+ a href => $url->('o', $_, $column_type) if $make_link;
+ lit $_ ? "\x{25BE}" : "\x{25B4}";
+ end 'a' if $make_link;
+ }
+ }
+ end 'td';
}
- }
- end 'tr';
-
- my %width = $f->{rwr} ? ( publication => 'max-width: 70px',
- voiced => 'max-width: 70px',
- ani_ero => 'max-width: 110px',
- notes => 'max-width: 400px') : ();
+ end 'tr';
+ end 'thead';
- $counter = 0;
- my $td_type = 'normal';
+ my $td_type = 0;
+ my $column_width = 0;
+ my @height = ((0) x $#column_types);
- while ($counter <= $#{$r}) {
- my $rel = @$r[$counter];
+ for my $r_index (0 .. $#{$r}) {
+ my $rel = @$r[$r_index];
Tr;
- foreach my $column (@column_types) {
- next if $height{$column}; # already drawn multirow box
+ for my $column_index (0 .. $#column_types) {
+ next if $height[$column_index] || $column_width; # already drawn multicell box
+
+ my $column = $column_types[$column_index];
# assume a height of 1, then add 1 for each following release with identical setting in $column
- $height{$column} = 1;
- while ($counter + $height{$column} <= $#{$r} && # end of release array not reached
- _compare_rel(@$r[$counter + $height{$column}], $rel, $column)) { # $column are identical in both releases
- $height{$column}++;
+ $height[$column_index] = 1;
+ while ($r_index + $height[$column_index] <= $#{$r} && # end of release array not reached
+ _compare_rel(@$r[$r_index + $height[$column_index]], $rel, $column, $c{$column}{na_for_patch})) { # $column are identical in both releases
+ $height[$column_index]++;
+ }
+
+ $column_width = 1;
+ if ($c{$column}{na_for_patch} && $rel->{patch}) {
+ my $skipped_legend = 0;
+ while (($column_index + $column_width + $skipped_legend) <= $#column_types && # end array not reached
+ (($c{$column_types[$column_index + $column_width + $skipped_legend]}{na_for_patch}) || # column with no data for patches
+ $column_types[$column_index + $column_width + $skipped_legend] eq 'legend' )) { # ignore legends
+ if ($column_types[$column_index + $column_width + $skipped_legend] eq 'legend') {
+ # column just right of a patch cell is a legend
+ # remember this and continue to check
+ $skipped_legend = 1;
+ } else {
+ if ($skipped_legend) {
+ # last column was a legend
+ # include this one in the patch cell since the columns on both sides will be included in the patch cell
+ $height[$column_index + $column_width] = $height[$column_index];
+ $column_width++;
+ $skipped_legend = 0;
+ }
+ $height[$column_index + $column_width] = $height[$column_index];
+ $column_width++;
+ }
+ }
}
- td class => $height{$column} > 1 ? 'multi' : $td_type,
- rowspan => $height{$column},
- $width{$column} ? (style => $width{$column}) : ();
- _write_release_string($self, $rel, $column);
+ td class => $height[$column_index] > 1 ? 'multi' : ($td_type ? 'bg' : 'normal'),
+ rowspan => $height[$column_index],
+ colspan => $column_width,
+ $column_width > 1 ? ( align => 'center' ) : (),
+ $c{$column}{column_width} && $f->{cw} ? (style => $c{$column}{column_width}) : ();
+ if ($c{$column}{na_for_patch} && $rel->{patch}) {
+ txt mt '_vnpage_na_for_patches';
+ } else {
+ _write_release_string($self, $rel, $column);
+ }
end 'td';
} continue {
- $height{$column}--;
+ $height[$column_index]-- if $height[$column_index];
+ $column_width-- if $column_width;
}
end 'tr';
} continue {
- $counter++;
-
# Toggle td_type
# This will provide the same effect as stripe table class,
# except rowspan settings will not cause the columns to go out of sync
- if ($td_type eq 'normal') {
- $td_type = 'bg';
- } else {
- $td_type = 'normal';
- }
+ $td_type = !$td_type;
}
end 'table';
end 'div';
@@ -248,25 +386,31 @@ sub _column_is_in_use {
when ('resolution') { return 1 if $rel->{resolution} }
when ('voiced') { return 1 if $rel->{voiced} }
when ('ani_ero') { return 1 if $rel->{ani_story}||$rel->{ani_ero} }
- when ('released') { return 1 if $rel->{released} }
+ when ('released') { return 1 }
when ('minage') { return 1 if $rel->{minage} != -1 }
when ('notes') { return 1 if $rel->{notes} }
}
}
- # No release has data set in the column in question
- return 0;
+ # No release has data set in the column in question and return value should be false
+ # However every row should be drawn (true) in case all releases are filtered out
+ return !@$r;
}
## Compare a specific variable in two releases
# Returns true if $variable is identical in both releases
sub _compare_rel {
- my($last_rel, $rel, $variable) = @_;
+ my($last_rel, $rel, $variable, $patch_na_var) = @_;
+
+ if ($patch_na_var) {
+ return 0 if !$rel->{patch} != !$last_rel->{patch};
+ return 1 if $rel->{patch} && $last_rel->{patch};
+ }
if ($variable eq 'resolution' || $variable eq 'voiced' || $variable eq 'released' || $variable eq 'minage') {
- $last_rel->{$variable} == $rel->{$variable}
+ return $last_rel->{$variable} == $rel->{$variable}
} elsif ($variable eq 'ani_ero') {
- $last_rel->{ani_story} eq $rel->{ani_story} &&
- $last_rel->{ani_ero} eq $rel->{ani_ero};
+ return $last_rel->{ani_story} eq $rel->{ani_story} &&
+ $last_rel->{ani_ero} eq $rel->{ani_ero};
} elsif ($variable eq 'media' || $variable eq 'platforms' || $variable eq 'languages'){
if (scalar @{$last_rel->{$variable}} != scalar @{$rel->{$variable}}) {
# last_rel and rel can't be identical if they even fail to have the same length of arrays
@@ -300,20 +444,19 @@ sub _compare_rel {
# everything from last_rel is found in rel
return 1;
} elsif ($variable eq 'type') {
- $last_rel->{type} eq $rel->{type} &&
- !$last_rel->{patch} == !$rel->{patch}
+ return $last_rel->{type} eq $rel->{type} &&
+ !$last_rel->{patch} == !$rel->{patch}
} elsif ($variable eq 'publication') {
- !$last_rel->{patch} == !$rel->{patch} &&
- !$last_rel->{freeware}== !$rel->{freeware} &&
- !$last_rel->{doujin} == !$rel->{doujin}
+ return !$last_rel->{patch} == !$rel->{patch} &&
+ !$last_rel->{freeware} == !$rel->{freeware} &&
+ !$last_rel->{doujin} == !$rel->{doujin}
} elsif ($variable eq 'notes') {
- $last_rel->{notes} eq $rel->{notes};
- } else {
- # Any line reaching this has no code to compare.
- # Treat everything as unique and return 0.
- # Note: certain types like title ends up here by design
- return 0;
+ return $last_rel->{notes} eq $rel->{notes};
}
+ # Any line reaching this has no code to compare.
+ # Treat everything as unique and return 0.
+ # Note: certain types like title ends up here by design
+ return 0;
}
## Draw the text/icon for a release
@@ -324,7 +467,6 @@ sub _write_release_string {
given ($variable) {
when ('title') { a href => "/r$rel->{id}", shorten $rel->{title}, 60 }
- when ('original') { txt $rel->{original} }
when ('type') { cssicon "rt$rel->{type}", mt "_rtype_$rel->{type}";
txt mt '_vnpage_rel_patch' if $rel->{patch};
}
@@ -332,27 +474,33 @@ sub _write_release_string {
cssicon "lang $_", mt "_lang_$_";
br if $_ ne $rel->{languages}[$#{$rel->{languages}}];
}
+ txt mt '_vnpage_release_unknown' if !@{$rel->{languages}};
}
when ('publication'){ txt mt $rel->{patch} ? '_relinfo_pub_patch' : '_relinfo_pub_nopatch', $rel->{freeware}?0:1, $rel->{doujin}?0:1 }
when ('platforms') { for(@{$rel->{platforms}}) {
cssicon $_, mt "_plat_$_";
br if $_ ne $rel->{platforms}[$#{$rel->{platforms}}];
}
+ txt mt '_vnpage_release_unknown' if !@{$rel->{platforms}};
}
when ('media') { for (@{$rel->{media}}) {
txt $self->{media}{$_->{medium}} ? $_->{qty}.' '.mt("_med_$_->{medium}", $_->{qty}) : mt("_med_$_->{medium}",1);
br if $_ ne $rel->{media}[$#{$rel->{media}}];
}
+ txt mt '_vnpage_release_unknown' if !@{$rel->{media}};
}
when ('resolution') { if($rel->{resolution}) {
my $res = $self->{resolutions}[$rel->{resolution}][0];
txt $res =~ /^_/ ? mt $res : $res;
+ } else {
+ txt mt '_vnpage_release_unknown';
}
}
when ('voiced') { txt mt '_voiced_'.$rel->{voiced}; }
when ('ani_ero') { txt join ', ',
$rel->{ani_story} ? mt('_relinfo_ani_story', mt '_animated_'.$rel->{ani_story}):(),
$rel->{ani_ero} ? mt('_relinfo_ani_ero', mt '_animated_'.$rel->{ani_ero} ):();
+ txt mt '_vnpage_release_unknown' if !$rel->{ani_story} && !$rel->{ani_ero};
}
when ('released') { lit $self->{l10n}->datestr($rel->{released}) }
when ('minage') { txt minage $rel->{minage} }