summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2010-12-19 16:01:58 +0100
committerYorhel <git@yorhel.nl>2010-12-19 16:01:58 +0100
commit6cf3b2a6f7cd3fb12282e823f42a64bcdf57d012 (patch)
tree92ae905399d7ab10e5c3f8ed0106d353749c6e7b
parenta129097a782ced2f2c3622f239809a937ecdb7d4 (diff)
RFC-01: Updated and improved /u+/list
I'm sure I broke all vnlist/rlist-related features on the rest of the site since I modified the DB abstractions. But these will all have to be updated/rewritten anyway.
-rw-r--r--data/lang.txt81
-rw-r--r--data/script.js20
-rw-r--r--data/style.css18
-rw-r--r--lib/VNDB/DB/ULists.pm116
-rw-r--r--lib/VNDB/Handler/ULists.pm105
5 files changed, 202 insertions, 138 deletions
diff --git a/data/lang.txt b/data/lang.txt
index a0b86b7f..515e0715 100644
--- a/data/lang.txt
+++ b/data/lang.txt
@@ -1137,70 +1137,70 @@ nl : Erg lang[index,_1,, (> 50 uur), (Clannad~, Umineko~, Fate/Stay Night)]
# VN list statuses
-:_rlst_rstat_0
+:_rlst_stat_0
en : Unknown
ru : Неизвестно
cs : Není známo
hu : Ismeretlen
nl : Onbekend
-:_rlst_rstat_1
+:_rlst_stat_1
en : Pending
ru : Ожидается
cs : V čekání
hu : Függő
nl : Bezig
-:_rlst_rstat_2
+:_rlst_stat_2
en : Obtained
ru : Приобретено
cs : Obdrženo
hu : Megszerezve
nl : In bezit
-:_rlst_rstat_3
+:_rlst_stat_3
en : On loan
ru : Взято напрокат
cs : Vypůjčeno
hu : Kölcsönadva
nl : Uitgeleend
-:_rlst_rstat_4
+:_rlst_stat_4
en : Deleted
ru : Удалено
cs : Smazáno
hu : Törölve
nl : Weggegooid
-:_rlst_vstat_0
+:_vnlst_stat_0
en : Unknown
ru : Неизвестно
cs : Není známo
hu : Ismeretlen
nl : Onbekend
-:_rlst_vstat_1
+:_vnlst_stat_1
en : Playing
ru : В процессе
cs : Ve hraní
hu : Játszás
nl : Mee bezig
-:_rlst_vstat_2
+:_vnlst_stat_2
en : Finished
ru : Завершено
cs : Dohráno
hu : Befejezve
nl : Uitgespeeld
-:_rlst_vstat_3
+:_vnlst_stat_3
en : Stalled
ru : Застряло
cs : Pozastaveno
hu : Leragadva
nl : Uitgesteld
-:_rlst_vstat_4
+:_vnlst_stat_4
en : Dropped
ru : Заброшено
cs : Vyřazeno
@@ -4903,6 +4903,13 @@ cs : Název
hu : Cím
nl : Titel
+:_rlist_col_status
+en : Status
+ru*:
+cs*:
+hu*:
+nl :
+
:_rlist_col_releases
en : Releases
ru : Выпуски
@@ -4917,26 +4924,26 @@ cs : Hodnocení
hu : Szavazat
nl : Stem
-:_rlist_selection
-en : -- with selected --
-ru : -- с выбранными --
-cs : -- s vybranými --
-hu : -- kiválasztva --
-nl : -- met geselecteerde items --
+:_rlist_withvn
+en : -- with selected VNs --
+ru*:
+cs*:
+hu*:
+nl : -- met geselecteerde VNs --
-:_rlist_changerel
-en : Change release status
-ru : Смена статуса выпуска
-cs : Změnit stav vydání
-hu : Kiadás állapotának megváltoztatása
-nl : Verander uitgavestatus
+:_rlist_withrel
+en : -- with selected releases --
+ru*:
+cs*:
+hu*:
+nl : -- met geselecteerde uitgaven --
-:_rlist_changeplay
-en : Change play status
-ru : Смена статуса игры
-cs : Změnit stav hraní
-hu : Játszás állapot megváltoztatása
-nl : Verander speelstatus
+:_rlist_changestat
+en : Change status
+ru*:
+cs*:
+hu*:
+nl : Verander status
:_rlist_del
en : remove from list
@@ -4945,12 +4952,20 @@ cs : odstranit z listu
hu : eltávolítás a listából
nl : verwijder uit lijst
+# label of the button. "Update!" in the commanding sense
+:_rlist_update
+en : Update
+ru*:
+cs*:
+hu*:
+nl :
+
:_rlist_releasenote
-en : * Obtained/finished/total
-ru : * Приобретено/прочитано/всего
-cs : * Sehnáno/dohráno/celkem
-hu : * Megszerezve/befejezve/összesen
-nl : * In bezit/uitgespeeld/totaal
+en : * Obtained/total
+ru : * Приобретено/всего
+cs : * Sehnáno/celkem
+hu : * Megszerezve/összesen
+nl : * In bezit/totaal
diff --git a/data/script.js b/data/script.js
index 4f0e808f..b30703d6 100644
--- a/data/script.js
+++ b/data/script.js
@@ -2216,7 +2216,7 @@ if(byId('batchedit')) {
};
}
-// collapse/expand row groups (/u+/list) (limited to one table on a page)
+// collapse/expand row groups (/u+/list)
if(byId('expandall')) {
var table = byId('expandall');
while(table.nodeName.toLowerCase() != 'table')
@@ -2227,11 +2227,14 @@ if(byId('expandall')) {
var alltoggle = function() {
allhid = !allhid;
var l = byClass(table, 'tr', 'collapse');
- for(var i=0; i<l.length; i++)
+ for(var i=0; i<l.length; i++) {
setClass(l[i], 'hidden', allhid);
- setText(byName(byId('expandall'), 'i')[0], allhid ? collapsed_icon : expanded_icon);
+ var sel = byName(l[i], 'input')[0];
+ if(sel) setClass(sel, 'hidden', allhid);
+ }
+ setText(byId('expandall'), allhid ? collapsed_icon : expanded_icon);
for(var i=0; i<heads.length; i++)
- setText(byName(heads[i], 'i')[0], allhid ? collapsed_icon : expanded_icon);
+ setText(heads[i], allhid ? collapsed_icon : expanded_icon);
return false;
}
byId('expandall').onclick = alltoggle;
@@ -2242,9 +2245,12 @@ if(byId('expandall')) {
if(l.length < 1)
return;
var hid = !hasClass(l[0], 'hidden');
- for(var i=0; i<l.length; i++)
+ for(var i=0; i<l.length; i++) {
setClass(l[i], 'hidden', hid);
- setText(byName(this, 'i')[0], hid ? collapsed_icon : expanded_icon);
+ var sel = byName(l[i], 'input')[0];
+ if(sel) setClass(sel, 'hidden', hid);
+ }
+ setText(this, hid ? collapsed_icon : expanded_icon);
};
for(var i=0; i<heads.length; i++)
heads[i].onclick = singletoggle;
@@ -2290,7 +2296,7 @@ if(byId('lang_select')) {
var f = function() {
var l = byName('input');
for(var i=0; i<l.length; i++)
- if(l[i].type == this.type && l[i].name == this.name)
+ if(l[i].type == this.type && l[i].name == this.name && !hasClass(l[i], 'hidden'))
l[i].checked = this.checked;
};
var l = byClass('input', 'checkall');
diff --git a/data/style.css b/data/style.css
index 6c043caf..433873d7 100644
--- a/data/style.css
+++ b/data/style.css
@@ -905,15 +905,15 @@ div.votelist td.tc2 { width: 50px; text-align: right; padding-right: 10px }
/***** User VN list browser ******/
#expandall, .collapse_but { cursor: pointer }
-#expandall i, .collapse_but i { font-style: normal }
-.browse.rlist .tc2 { width: 100px; }
-.browse.rlist .tc3 { width: 70px; }
-.browse.rlist .relhid .tc1 { padding-left: 40px; width: 70px; }
-.browse.rlist .relhid .tc1.own { padding: 0 0 0 25px; width: 95px }
-.browse.rlist .relhid input { margin-right: 5px }
-.browse.rlist .relhid .tc2 { padding: 0; width: 30px; }
-.browse.rlist .relhid .tc3 { width: auto }
-.browse.rlist .relhid .tc4 { text-align: right }
+.browse.rlist .tc1 { width: 16px; padding-bottom: 0 }
+.browse.rlist .tc2 { width: 16px; padding-bottom: 0 }
+.browse.rlist .tc3 { width: 60px }
+.browse.rlist .tc4 { width: 60px; text-align: right; padding-top: 0; padding-bottom: 0 }
+.browse.rlist .tc6 { width: 100px }
+.browse.rlist .relhid .tc6 { padding-left: 15px; width: auto }
+.browse.rlist .tc7 { width: 90px }
+.browse.rlist .tc8 { width: 70px }
+.browse.rlist tfoot select { width: 200px }
/***** User notifications *****/
diff --git a/lib/VNDB/DB/ULists.pm b/lib/VNDB/DB/ULists.pm
index e52cbf37..1aedfe80 100644
--- a/lib/VNDB/DB/ULists.pm
+++ b/lib/VNDB/DB/ULists.pm
@@ -7,56 +7,61 @@ use Exporter 'import';
our @EXPORT = qw|
- dbVNListGet dbVNListList dbVNListAdd dbVNListDel
+ dbRListGet dbVNListGet dbVNListList dbVNListAdd dbVNListDel dbRListAdd dbRListDel
dbVoteGet dbVoteStats dbVoteAdd dbVoteDel
dbWishListGet dbWishListAdd dbWishListDel
|;
-# Simpler and more efficient version of dbVNListList below
-# %options->{ uid rid }
-sub dbVNListGet {
+# Options: uid rid
+sub dbRListGet {
my($self, %o) = @_;
my %where = (
'uid = ?' => $o{uid},
- $o{rid} && !ref $o{rid} ? (
- 'rid = ?' => $o{rid} ) : (),
- $o{rid} && ref $o{rid} ? (
- 'rid IN(!l)' => [$o{rid}] ) : (),
+ $o{rid} ? ('rid IN(!l)' => [ ref $o{rid} ? $o{rid} : [$o{rid}] ]) : (),
);
return $self->dbAll(q|
- SELECT uid, rid, rstat, vstat
+ SELECT uid, rid, rstat AS status
FROM rlists
!W|,
\%where
);
}
+# Options: uid vid
+sub dbVNListGet {
+ my($self, %o) = @_;
-# %options->{ uid char voted page results sort reverse }
+ my %where = (
+ 'uid = ?' => $o{uid},
+ $o{vid} ? ('vid IN(!l)' => [ ref $o{vid} ? $o{vid} : [$o{vid}] ]) : (),
+ );
+
+ return $self->dbAll(q|
+ SELECT uid, vid, status
+ FROM vnlists
+ !W|,
+ \%where
+ );
+}
+
+
+# Options: uid char voted page results sort reverse
# sort: title vote
-# NOTE: this function is mostly copied from 1.x, may need some rewriting...
sub dbVNListList {
my($self, %o) = @_;
-
$o{results} ||= 50;
$o{page} ||= 1;
- $o{voted} ||= 0; # -1: only non-voted, 0: all, 1: only voted
-
- # construct the global WHERE clause
- my $where = $o{voted} != -1 ? 'vo.vote IS NOT NULL' : '';
- $where .= ($where?' OR ':'').q|v.id = ANY(ARRAY(
- SELECT irv.vid
- FROM rlists irl
- JOIN releases ir ON ir.id = irl.rid
- JOIN releases_vn irv ON irv.rid = ir.latest
- WHERE uid = ?
- ))| if $o{voted} != 1;
- $where = '('.$where.') AND LOWER(SUBSTR(vr.title, 1, 1)) = \''.$o{char}.'\'' if $o{char};
- $where = '('.$where.') AND (ASCII(vr.title) < 97 OR ASCII(vr.title) > 122) AND (ASCII(vr.title) < 65 OR ASCII(vr.title) > 90)' if defined $o{char} && !$o{char};
- $where = '('.$where.') AND vo.vote IS NULL' if $o{voted} == -1;
+
+ my %where = (
+ 'vl.uid = ?' => $o{uid},
+ defined($o{voted}) ? ('vo.vote !s NULL' => $o{voted} ? 'IS NOT' : 'IS') : (),
+ $o{char} ? ('LOWER(SUBSTR(vr.title, 1, 1)) = ?' => $o{char} ) : (),
+ defined $o{char} && !$o{char} ? (
+ '(ASCII(vr.title) < 97 OR ASCII(vr.title) > 122) AND (ASCII(vr.title) < 65 OR ASCII(vr.title) > 90)' => 1 ) : (),
+ );
my $order = sprintf {
title => 'vr.title %s',
@@ -65,14 +70,14 @@ sub dbVNListList {
# execute query
my($r, $np) = $self->dbPage(\%o, qq|
- SELECT vr.vid, vr.title, vr.original, COALESCE(vo.vote, 0) AS vote
- FROM vn v
+ SELECT vr.vid, vr.title, vr.original, vl.status, COALESCE(vo.vote, 0) AS vote
+ FROM vnlists vl
+ JOIN vn v ON v.id = vl.vid
JOIN vn_rev vr ON vr.id = v.latest
- !s JOIN votes vo ON vo.vid = v.id AND vo.uid = ?
- WHERE $where
+ LEFT JOIN votes vo ON vo.vid = vl.vid AND vo.uid = vl.uid
+ !W
ORDER BY !s|,
- $o{voted} == 1 ? '' : 'LEFT', $o{uid}, # JOIN if we only want votes, LEFT JOIN if we also want rlist items
- $o{voted} != 1 ? $o{uid} : (), $order
+ \%where, $order
);
# fetch releases and link to VNs
@@ -83,7 +88,7 @@ sub dbVNListList {
} @$r;
my $rel = $self->dbAll(q|
- SELECT rv.vid, rr.rid, r.latest, rr.title, rr.original, rr.released, rr.type, rl.rstat, rl.vstat
+ SELECT rv.vid, rr.rid, r.latest, rr.title, rr.original, rr.released, rr.type, rl.rstat AS status
FROM rlists rl
JOIN releases r ON rl.rid = r.id
JOIN releases_rev rr ON rr.id = r.latest
@@ -114,35 +119,54 @@ sub dbVNListList {
}
-# %options->{ uid rid rstat vstat }
+# Arguments: uid vid status
+# vid can be an arrayref only when the rows are already present, in which case an update is done
sub dbVNListAdd {
- my($self, %o) = @_;
+ my($self, $uid, $vid, $stat) = @_;
+ $self->dbExec(
+ 'UPDATE vnlists SET status = ? WHERE uid = ? AND vid IN(!l)',
+ $stat, $uid, ref($vid) ? $vid : [ $vid ]
+ )
+ ||
+ $self->dbExec(
+ 'INSERT INTO vnlists (uid, vid, status) VALUES(?, ?, ?)',
+ $uid, $vid, $stat
+ );
+}
- my %s = (
- defined $o{rstat} ? ( 'rstat = ?', $o{rstat} ) : (),
- defined $o{vstat} ? ( 'vstat = ?', $o{vstat} ) : (),
+
+# Arguments: uid, vid
+sub dbVNListDel {
+ my($self, $uid, $vid) = @_;
+ $self->dbExec(
+ 'DELETE FROM vnlists WHERE uid = ? AND vid IN(!l)',
+ $uid, ref($vid) ? $vid : [ $vid ]
);
- $o{rstat}||=0;
- $o{vstat}||=0;
+}
+
+# Arguments: uid rid status
+# rid can be an arrayref only when the rows are already present, in which case an update is done
+sub dbRListAdd {
+ my($self, $uid, $rid, $stat) = @_;
$self->dbExec(
- 'UPDATE rlists !H WHERE uid = ? AND rid IN(!l)',
- \%s, $o{uid}, ref($o{rid}) eq 'ARRAY' ? $o{rid} : [ $o{rid} ]
+ 'UPDATE rlists SET rstat = ? WHERE uid = ? AND rid IN(!l)',
+ $stat, $uid, ref($rid) ? $rid : [ $rid ]
)
||
$self->dbExec(
- 'INSERT INTO rlists (uid, rid, rstat, vstat) VALUES(!l)',
- [@o{qw| uid rid rstat vstat |}]
+ 'INSERT INTO rlists (uid, rid, rstat) VALUES(?, ?, ?)',
+ $uid, $rid, $stat
);
}
# Arguments: uid, rid
-sub dbVNListDel {
+sub dbRListDel {
my($self, $uid, $rid) = @_;
$self->dbExec(
'DELETE FROM rlists WHERE uid = ? AND rid IN(!l)',
- $uid, ref($rid) eq 'ARRAY' ? $rid : [ $rid ]
+ $uid, ref($rid) ? $rid : [ $rid ]
);
}
diff --git a/lib/VNDB/Handler/ULists.pm b/lib/VNDB/Handler/ULists.pm
index c8119000..cac1acec 100644
--- a/lib/VNDB/Handler/ULists.pm
+++ b/lib/VNDB/Handler/ULists.pm
@@ -278,26 +278,29 @@ sub vnlist {
if($own && $self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
my $frm = $self->formValidate(
- { name => 'sel', required => 0, default => 0, multi => 1, template => 'int' },
- { name => 'batchedit', required => 1, enum => [ 'del', map("r$_", @{$self->{rlst_rstat}}), map("v$_", @{$self->{rlst_vstat}}) ] },
+ { name => 'vid', required => 0, default => 0, multi => 1, template => 'int' },
+ { name => 'rid', required => 0, default => 0, multi => 1, template => 'int' },
+ { name => 'vns', required => 1, enum => [ -2, -1, @{$self->{rlst_vstat}} ] },
+ { name => 'rel', required => 1, enum => [ -2, -1, @{$self->{rlst_rstat}} ] },
);
- if(!$frm->{_err} && @{$frm->{sel}} && $frm->{sel}[0]) {
- $self->dbVNListDel($uid, $frm->{sel}) if $frm->{batchedit} eq 'del';
- $self->dbVNListAdd(
- rid => $frm->{sel},
- uid => $uid,
- $frm->{batchedit} =~ /^([rv])(\d+)$/ && $1 eq 'r' ? (rstat => $2) : (vstat => $2)
- ) if $frm->{batchedit} ne 'del';
+ my @vid = grep $_ > 0, @{$frm->{vid}};
+ my @rid = grep $_ > 0, @{$frm->{rid}};
+ if(!$frm->{_err} && @vid && $frm->{vns} > -2) {
+ $self->dbVNListDel($uid, \@vid) if $frm->{vns} == -1;
+ $self->dbVNListAdd($uid, \@vid, $frm->{vns}) if $frm->{vns} >= 0;
+ }
+ if(!$frm->{_err} && @rid && $frm->{rel} > -2) {
+ $self->dbRListDel($uid, \@rid) if $frm->{rel} == -1;
+ $self->dbRListAdd($uid, \@rid, $frm->{rel}) if $frm->{rel} >= 0;
}
}
-
my($list, $np) = $self->dbVNListList(
uid => $uid,
results => 50,
page => $f->{p},
sort => $f->{s}, reverse => $f->{o} eq 'd',
- voted => $f->{v},
+ voted => $f->{v} == 0 ? undef : $f->{v} < 0 ? 0 : $f->{v},
$f->{c} ne 'all' ? (char => $f->{c}) : (),
);
@@ -351,66 +354,82 @@ sub _vnlist_browse {
sorturl => $url->(),
pageurl => $url->('page'),
header => [
- [ mt('_rlist_col_title') => 'title', 3 ],
- sub { td class => 'tc2', id => 'expandall'; lit '<i>&#9656;</i>'.mt('_rlist_col_releases').'*'; end; },
+ [ '' ],
+ sub { td class => 'tc2', id => 'expandall'; lit '&#9656;'; end; },
+ [ mt('_rlist_col_title') => 'title' ],
+ [ '' ], [ '' ],
+ [ mt('_rlist_col_status') ],
+ [ mt('_rlist_col_releases').'*' ],
[ mt('_rlist_col_vote') => 'vote' ],
],
row => sub {
my($s, $n, $i) = @_;
Tr $n % 2 == 0 ? (class => 'odd') : ();
- td class => 'tc1', colspan => 3;
+ td class => 'tc1'; input type => 'checkbox', name => 'vid', value => $i->{vid} if $own; end;
+ if(@{$i->{rels}}) {
+ td class => 'tc2 collapse_but', id => "vid$i->{vid}"; lit '&#9656;'; end;
+ } else {
+ td class => 'tc2', '';
+ }
+ td class => 'tc3_5', colspan => 3;
a href => "/v$i->{vid}", title => $i->{original}||$i->{title}, shorten $i->{title}, 70;
end;
- td class => 'tc2'.(@{$i->{rels}} ? ' collapse_but' : ''), id => 'vid'.$i->{vid};
- lit '<i>&#9656;</i>';
- my $obtained = grep $_->{rstat}==2, @{$i->{rels}};
- my $finished = grep $_->{vstat}==2, @{$i->{rels}};
- my $txt = sprintf '%d/%d/%d', $obtained, $finished, scalar @{$i->{rels}};
- $txt = qq|<b class="done">$txt</b>| if $finished > $obtained || $finished && $finished == $obtained;
- $txt = qq|<b class="todo">$txt</b>| if $obtained > $finished;
+ td class => 'tc6', $i->{status} ? mt '_vnlst_stat_'.$i->{status} : '';
+ td class => 'tc7';
+ my $obtained = grep $_->{status}==2, @{$i->{rels}};
+ my $total = scalar @{$i->{rels}};
+ my $txt = sprintf '%d/%d', $obtained, $total;
+ $txt = qq|<b class="done">$txt</b>| if $total && $obtained == $total;
+ $txt = qq|<b class="todo">$txt</b>| if $obtained < $total;
lit $txt;
end;
- td class => 'tc3', $i->{vote} || '-';
+ td class => 'tc8', $i->{vote} || '-';
end;
for (@{$i->{rels}}) {
- Tr class => "collapse relhid collapse_vid$i->{vid}";
- td class => 'tc1'.($own ? ' own' : '');
- input type => 'checkbox', name => 'sel', value => $_->{rid}
- if $own;
- lit $self->{l10n}->datestr($_->{released});
- end;
+ Tr class => "collapse relhid collapse_vid$i->{vid}".($n%2 ? '':' odd');
+ td class => 'tc1', '';
td class => 'tc2';
+ input type => 'checkbox', name => 'rid', value => $_->{rid} if $own;
+ end;
+ td class => 'tc3', $self->{l10n}->datestr($_->{released});
+ td class => 'tc4';
cssicon "lang $_", mt "_lang_$_" for @{$_->{languages}};
cssicon "rt$_->{type}", mt "_rtype_$_->{type}";
end;
- td class => 'tc3';
+ td class => 'tc5';
a href => "/r$_->{rid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 50;
end;
- td colspan => 2, class => 'tc4';
- lit liststat($_);
- end;
+ td class => 'tc6', $_->{status} ? mt '_rlst_stat_'.$_->{status} : '';
+ td class => 'tc7_8', colspan => 2, '';
end;
}
},
$own ? (footer => sub {
Tr;
- td class => 'tc1', colspan => 3;
- Select id => 'batchedit', name => 'batchedit';
- option mt '_rlist_selection';
- optgroup label => mt '_rlist_changerel';
- option value => "r$_", mt "_rlst_rstat_$_"
- for (@{$self->{rlst_rstat}});
- end;
- optgroup label => mt '_rlist_changeplay';
- option value => "v$_", mt "_rlst_vstat_$_"
+ td class => 'tc1'; input type => 'checkbox', name => 'vid', value => -1, class => 'checkall'; end;
+ td class => 'tc2'; input type => 'checkbox', name => 'rid', value => -1, class => 'checkall'; end;
+ td class => 'tc3_6', colspan => 4;
+ Select id => 'vns', name => 'vns';
+ option value => -2, mt '_rlist_withvn';
+ optgroup label => mt '_rlist_changestat';
+ option value => $_, mt "_vnlst_stat_$_"
for (@{$self->{rlst_vstat}});
end;
- option value => 'del', mt '_rlist_del';
+ option value => -1, mt '_rlist_del';
+ end;
+ Select id => 'rel', name => 'rel';
+ option value => -2, mt '_rlist_withrel';
+ optgroup label => mt '_rlist_changestat';
+ option value => $_, mt "_rlst_stat_$_"
+ for (@{$self->{rlst_rstat}});
+ end;
+ option value => -1, mt '_rlist_del';
end;
+ input type => 'submit', value => mt '_rlist_update';
end;
- td class => 'tc2', colspan => 2, mt '_rlist_releasenote';
+ td class => 'tc7_8', colspan => 2, mt '_rlist_releasenote';
end;
}) : (),
);