diff options
-rw-r--r-- | data/js/main.js | 4 | ||||
-rw-r--r-- | data/js/misc.js | 19 | ||||
-rw-r--r-- | data/js/prodrel.js | 108 | ||||
-rw-r--r-- | data/js/tabs.js | 49 | ||||
-rw-r--r-- | data/style.css | 43 | ||||
-rw-r--r-- | lib/VNDB/DB/Misc.pm | 25 | ||||
-rw-r--r-- | lib/VNDB/DB/Producers.pm | 21 | ||||
-rw-r--r-- | lib/VNDB/Handler/Producers.pm | 214 | ||||
-rw-r--r-- | lib/VNDB/Handler/Releases.pm | 25 | ||||
-rw-r--r-- | lib/VNDB/Util/CommonHTML.pm | 190 |
10 files changed, 9 insertions, 689 deletions
diff --git a/data/js/main.js b/data/js/main.js index f335f1f5..8f3f6ca2 100644 --- a/data/js/main.js +++ b/data/js/main.js @@ -31,13 +31,9 @@ VARS.resolutions = [ //include dropdown.js //include dateselector.js //include dropdownsearch.js -//include tabs.js // Page/functionality-specific widgets //include filter.js //include misc.js -// Producer editing (/p+/edit) -//include prodrel.js - // @license-end diff --git a/data/js/misc.js b/data/js/misc.js index 9c151eae..9658bccf 100644 --- a/data/js/misc.js +++ b/data/js/misc.js @@ -1,22 +1,3 @@ -// expand/collapse release listing (/p+) -(function(){ - var lnk = byId('expandprodrel'); - if(!lnk) - return; - function setexpand() { - var exp = !(getCookie('prodrelexpand') == 1); - setText(lnk, exp ? 'collapse' : 'expand'); - setClass(byId('prodrel'), 'collapse', !exp); - }; - lnk.onclick = function () { - setCookie('prodrelexpand', getCookie('prodrelexpand') == 1 ? 0 : 1); - setexpand(); - return false; - }; - setexpand(); -})(); - - // search tabs (function(){ function click() { diff --git a/data/js/prodrel.js b/data/js/prodrel.js deleted file mode 100644 index ec6082e3..00000000 --- a/data/js/prodrel.js +++ /dev/null @@ -1,108 +0,0 @@ -function prrLoad() { - // read the current relations - var rels = byId('prodrelations').value.split('|||'); - for(var i=0; i<rels.length && rels[0].length>1; i++) { - var rel = rels[i].split(',', 3); - prrAdd(rel[0], rel[1], rel[2]); - } - prrEmpty(); - - // bind the add-link - byName(byClass(byId('relation_new'), 'td', 'tc_add')[0], 'a')[0].onclick = prrFormAdd; - - // dropdown - dsInit(byName(byClass(byId('relation_new'), 'td', 'tc_prod')[0], 'input')[0], '/xml/producers.xml?q=', function(item, tr) { - tr.appendChild(tag('td', { style: 'text-align: right; padding-right: 5px'}, 'p'+item.getAttribute('id'))); - tr.appendChild(tag('td', shorten(item.firstChild.nodeValue, 40))); - }, function(item) { - return 'p'+item.getAttribute('id')+':'+item.firstChild.nodeValue; - }, prrFormAdd); -} - -function prrAdd(rel, pid, title) { - var sel = tag('select', {onchange: prrSerialize}); - var ops = byName(byClass(byId('relation_new'), 'td', 'tc_rel')[0], 'select')[0].options; - for(var i=0; i<ops.length; i++) - sel.appendChild(tag('option', {value: ops[i].value, selected: ops[i].value==rel}, getText(ops[i]))); - - byId('relation_tbl').appendChild(tag('tr', {id:'relation_tr_'+pid}, - tag('td', {'class':'tc_prod' }, 'p'+pid+':', tag('a', {href:'/p'+pid}, shorten(title, 40))), - tag('td', {'class':'tc_rel' }, sel), - tag('td', {'class':'tc_add' }, tag('a', {href:'#', onclick:prrDel}, 'remove')) - )); - - prrEmpty(); -} - -function prrEmpty() { - var tbl = byId('relation_tbl'); - if(byName(tbl, 'tr').length < 1) - tbl.appendChild(tag('tr', {id:'relation_tr_none'}, tag('td', {colspan:4}, 'Nothing selected.'))); - else if(byId('relation_tr_none')) - tbl.removeChild(byId('relation_tr_none')); -} - -function prrSerialize() { - var r = []; - var trs = byName(byId('relation_tbl'), 'tr'); - for(var i=0; i<trs.length; i++) { - if(trs[i].id == 'relation_tr_none') - continue; - var rel = byName(byClass(trs[i], 'td', 'tc_rel')[0], 'select')[0]; - r[r.length] = [ - rel.options[rel.selectedIndex].value, - trs[i].id.substr(12), - getText(byName(byClass(trs[i], 'td', 'tc_prod')[0], 'a')[0]) - ].join(','); - } - byId('prodrelations').value = r.join('|||'); -} - -function prrDel() { - var tr = this; - while(tr.nodeName.toLowerCase() != 'tr') - tr = tr.parentNode; - byId('relation_tbl').removeChild(tr); - prrSerialize(); - prrEmpty(); - return false; -} - -function prrFormAdd() { - var relnew = byId('relation_new'); - var txt = byName(byClass(relnew, 'td', 'tc_prod')[0], 'input')[0]; - var sel = byName(byClass(relnew, 'td', 'tc_rel')[0], 'select')[0]; - var lnk = byName(byClass(relnew, 'td', 'tc_add')[0], 'a')[0]; - var input = txt.value; - - if(!input.match(/^p[0-9]+/)) { - alert('Producer textbox should start with an ID (e.g. "p7:")'); - return false; - } - - txt.disabled = sel.disabled = true; - txt.value = 'Loading...'; - setText(lnk, 'Loading...'); - - ajax('/xml/producers.xml?q='+encodeURIComponent(input), function(hr) { - txt.disabled = sel.disabled = false; - txt.value = ''; - setText(lnk, 'add'); - - var items = hr.responseXML.getElementsByTagName('item'); - if(items.length < 1) - return alert('Producer not found'); - - var id = items[0].getAttribute('id'); - if(byId('relation_tr_'+id)) - return alert('Producer already selected!'); - - prrAdd(sel.options[sel.selectedIndex].value, id, items[0].firstChild.nodeValue); - sel.selectedIndex = 0; - prrSerialize(); - }); - return false; -} - -if(byId('prodrelations')) - prrLoad(); diff --git a/data/js/tabs.js b/data/js/tabs.js deleted file mode 100644 index 470bd077..00000000 --- a/data/js/tabs.js +++ /dev/null @@ -1,49 +0,0 @@ -/* Javascript tabs. General usage: - * - * <ul id="jt_select"> - * <li><a href="#<name>" id="jt_sel_<name>">..</a></li> - * .. - * </ul> - * - * Can then be used to show/hide the following box: - * - * <div id="jt_box_<name>"> .. </div> - * - * The name of the active box will be set to and (at page load) read from - * location.hash. The parent node of the active link will get the 'tabselected' - * class. A link with the special name "all" will display all boxes associated - * with jt_select links. - * - * Only one jt_select list-of-tabs can be used on a single page. - */ -var links = byId('jt_select') ? byName(byId('jt_select'), 'a') : []; - -function init() { - var sel; - var first; - for(var i=0; i<links.length; i++) { - links[i].onclick = function() { set(this.id); return false }; - if(!first) - first = links[i].id; - if(location.hash && links[i].id == 'jt_sel_'+location.hash.substr(1)) - sel = links[i].id; - } - if(first) - set(sel||first, 1); -} - -function set(which, nolink) { - which = which.substr(7); - - for(var i=0; i<links.length; i++) { - var name = links[i].id.substr(7); - if(name != 'all') - setClass(byId('jt_box_'+name), 'hidden', which != 'all' && which != name); - setClass(links[i].parentNode, 'tabselected', name == which); - } - - if(!nolink) - location.href = '#'+which; -} - -init(); diff --git a/data/style.css b/data/style.css index 81076de0..7f4a59a0 100644 --- a/data/style.css +++ b/data/style.css @@ -589,17 +589,6 @@ div.producerbrowse { padding-bottom: 10px } .producerbrowse ul li abbr { margin-right: 5px; margin-top: 1px; } -/***** Producer edit *****/ - -#jt_box_pedit_rel table { margin-bottom: 10px; } -#jt_box_pedit_rel h2 { margin: 0 0 3px 0px; } -#jt_box_pedit_rel td { padding: 1px 2px; vertical-align: middle; } -#jt_box_pedit_rel td.tc_prod { width: 290px; padding-left: 10px } -#jt_box_pedit_rel td.tc_add { width: 40px; text-align: left } -#jt_box_pedit_rel td.tc_prod input { width: 280px; } -#jt_box_pedit_rel td.tc_rel select { width: 130px; } - - /***** Release page *****/ @@ -711,35 +700,15 @@ div.charsum_list .charsum_bubble { /***** Staff edit *****/ -#jt_box_vn_cast #cast_import { clear: right; float: right; } -#jt_box_vn_cast table, -#jt_box_vn_staff table { margin-bottom: 10px; margin-left: 20px } -#jt_box_vn_cast h2, -#jt_box_vn_staff h2 { margin: 0 0 3px 0px; } -#jt_box_vn_cast td, -#jt_box_vn_staff td { padding: 1px 2px; vertical-align: middle; } -#jt_box_vn_cast td.tc_role, -#jt_box_vn_cast td.tc_role select, -#jt_box_vn_staff td.tc_role, -#jt_box_vn_staff td.tc_role select { width: 120px } -#jt_box_vn_cast td.tc_staff, -#jt_box_vn_staff td.tc_staff, -.staffedit td.tc_name, -.staffedit td.tc_original { width: 200px } -#jt_box_vn_cast td.tc_staff input, -#jt_box_vn_staff td.tc_staff input, -.staffedit td.tc_name input, -.staffedit td.tc_original input { width: 200px } -#jt_box_vn_cast td.tc_note, -#jt_box_vn_cast td.tc_note input, -#jt_box_vn_staff td.tc_note, -#jt_box_vn_staff td.tc_note input { width: 250px } -#jt_box_vn_cast td.tc_add, -#jt_box_vn_staff td.tc_add, -.staffedit td.tc_add { width: 40px; text-align: left; white-space: nowrap } +.staffedit td.tc_name, +.staffedit td.tc_original { width: 200px } +.staffedit td.tc_name input, +.staffedit td.tc_original input { width: 200px } +.staffedit td.tc_add { width: 40px; text-align: left; white-space: nowrap } .staffedit table.names td { padding: 1px 2px; vertical-align: middle; } .staffedit table.names tr.alias_new td { padding-top: 8px } + /***** Documentation pages *****/ .docs { padding: 0 15% 20px 15%; line-height: 1.4 } diff --git a/lib/VNDB/DB/Misc.pm b/lib/VNDB/DB/Misc.pm index 2bd18c4c..525d5975 100644 --- a/lib/VNDB/DB/Misc.pm +++ b/lib/VNDB/DB/Misc.pm @@ -6,33 +6,10 @@ use warnings; use Exporter 'import'; our @EXPORT = qw| - dbItemEdit dbRevisionGet + dbRevisionGet |; -# Inserts a new revision into the database -# Arguments: type [vrpcsd], itemid, rev, %options->{ editsum uid ihid ilock + db[item]RevisionInsert } -# rev = changes.rev of the revision this edit is based on, undef to create a new DB item -# Returns: { itemid, chid, rev } -sub dbItemEdit { - my($self, $type, $itemid, $rev, %o) = @_; - - $self->dbExec('SELECT edit_!s_init(?, ?)', $type, $itemid, $rev); - $self->dbExec('UPDATE edit_revision !H', { - 'requester = ?' => $o{uid}||$self->authInfo->{id}, - 'ip = ?' => $self->reqIP, - 'comments = ?' => $o{editsum}, - exists($o{ihid}) ? ('ihid = ?' => $o{ihid} ?1:0) : (), - exists($o{ilock}) ? ('ilock = ?' => $o{ilock}?1:0) : (), - }); - - die if $type ne 'p'; - $self->dbProducerRevisionInsert(\%o) if $type eq 'p'; - - return $self->dbRow('SELECT * FROM edit_!s_commit()', $type); -} - - # Options: type, itemid, uid, auto, hidden, edit, page, results, releases sub dbRevisionGet { my($self, %o) = @_; diff --git a/lib/VNDB/DB/Producers.pm b/lib/VNDB/DB/Producers.pm index 9497a8eb..c9d4f95f 100644 --- a/lib/VNDB/DB/Producers.pm +++ b/lib/VNDB/DB/Producers.pm @@ -5,7 +5,7 @@ use strict; use warnings; use Exporter 'import'; -our @EXPORT = qw|dbProducerGet dbProducerGetRev dbProducerRevisionInsert|; +our @EXPORT = qw|dbProducerGet dbProducerGetRev|; # options: results, page, id, search, char, sort, inc_hidden @@ -104,24 +104,5 @@ sub _enrich { return wantarray ? ($r, $np) : $r; } - -# Updates the edit_* tables, used from dbItemEdit() -# Arguments: { columns in producers_rev + relations }, -sub dbProducerRevisionInsert { - my($self, $o) = @_; - - my %set = map exists($o->{$_}) ? (qq|"$_" = ?|, $o->{$_}) : (), - qw|name original website l_wp l_wikidata type lang desc alias|; - $self->dbExec('UPDATE edit_producers !H', \%set) if keys %set; - - if($o->{relations}) { - $self->dbExec('DELETE FROM edit_producers_relations'); - my $q = join ',', map '(?,?)', @{$o->{relations}}; - my @q = map +($_->[1], $_->[0]), @{$o->{relations}}; - $self->dbExec("INSERT INTO edit_producers_relations (pid, relation) VALUES $q", @q) if @q; - } -} - - 1; diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm index 6e70e512..e25e3320 100644 --- a/lib/VNDB/Handler/Producers.pm +++ b/lib/VNDB/Handler/Producers.pm @@ -9,225 +9,11 @@ use VNDB::Types; TUWF::register( - qr{old/p/add} => \&addform, - qr{old/p(?:([1-9]\d*)(?:\.([1-9]\d*))?/edit|/new)} - => \&edit, qr{p/([a-z0]|all)} => \&list, qr{xml/producers\.xml} => \&pxml, ); -sub addform { - my $self = shift; - return $self->htmlDenied if !$self->authCan('edit'); - - my $frm; - my $l = []; - if($self->reqMethod eq 'POST') { - return if !$self->authCheckCode; - $frm = $self->formValidate( - { post => 'name', maxlength => 200 }, - { post => 'original', required => 0, maxlength => 200, default => '' }, - { post => 'alias', required => 0, maxlength => 500, default => '' }, - { post => 'continue_ign',required => 0 }, - ); - - # look for duplicates - if(!$frm->{_err} && !$frm->{continue_ign}) { - $l = $self->dbProducerGet(search => $frm->{name}, what => 'extended', results => 50, inc_hidden => 1); - push @$l, @{$self->dbProducerGet(search => $frm->{original}, what => 'extended', results => 50, inc_hidden => 1)} if $frm->{original}; - $_ && push @$l, @{$self->dbProducerGet(search => $_, what => 'extended', results => 50, inc_hidden => 1)} for(split /\n/, $frm->{alias}); - my %ids = map +($_->{id}, $_), @$l; - $l = [ map $ids{$_}, sort { $ids{$a}{name} cmp $ids{$b}{name} } keys %ids ]; - } - - return edit($self, undef, undef, 1) if !@$l && !$frm->{_err}; - } - - $self->htmlHeader(title => 'Add a new producer', noindex => 1); - if(@$l) { - div class => 'mainbox'; - h1 'Possible duplicates found'; - div class => 'warning'; - p; - txt 'The following is a list of producers that match the name(s) you gave.' - .' Please check this list to avoid creating a duplicate producer entry.' - .' Be especially wary of items that have been deleted! To see why an entry has been deleted, click on its title.'; - br; br; - txt 'To add the producer anyway, hit the "Continue and ignore duplicates" button below.'; - end; - end; - ul; - for(@$l) { - li; - a href => "/p$_->{id}", title => $_->{original}||$_->{name}, "p$_->{id}: ".shorten($_->{name}, 50); - b class => 'standout', ' deleted' if $_->{hidden}; - end; - } - end; - end 'div'; - } - - $self->htmlForm({ frm => $frm, action => '/old/p/add', continue => @$l ? 2 : 1 }, - vn_add => [ 'Add a new producer', - [ input => name => 'Name (romaji)', short => 'name' ], - [ input => name => 'Original name', short => 'original' ], - [ static => content => 'The original name of the producer, leave blank if it is already in the Latin alphabet.' ], - [ textarea => short => 'alias', name => 'Aliases', rows => 4 ], - [ static => content => '(Un)official aliases, separated by a newline.' ], - ]); - $self->htmlFooter; -} - - -# pid as argument = edit producer -# no arguments = add new producer -sub edit { - my($self, $pid, $rev, $nosubmit) = @_; - - my $p = $pid && $self->dbProducerGetRev(id => $pid, what => 'extended relations', rev => $rev)->[0]; - return $self->resNotFound if $pid && !$p->{id}; - $rev = undef if !$p || $p->{lastrev}; - - return $self->htmlDenied if !$self->authCan('edit') - || $pid && (($p->{locked} || $p->{hidden}) && !$self->authCan('dbmod')); - - my %b4 = !$pid ? () : ( - (map { $_ => $p->{$_} } qw|type name original lang website l_wikidata desc alias ihid ilock|), - prodrelations => join('|||', map $_->{relation}.','.$_->{id}.','.$_->{name}, sort { $a->{id} <=> $b->{id} } @{$p->{relations}}), - ); - my $frm; - - if($self->reqMethod eq 'POST') { - return if !$nosubmit && !$self->authCheckCode; - $frm = $self->formValidate( - { post => 'type', required => !$nosubmit, enum => [ keys %PRODUCER_TYPE ] }, - { post => 'name', maxlength => 200 }, - { post => 'original', required => 0, maxlength => 200, default => '' }, - { post => 'alias', required => 0, maxlength => 500, default => '' }, - { post => 'lang', required => !$nosubmit, enum => [ keys %LANGUAGE ] }, - { post => 'website', required => 0, maxlength => 250, default => '', template => 'weburl' }, - { post => 'l_wikidata', required => 0, template => 'wikidata' }, - { post => 'desc', required => 0, maxlength => 5000, default => '' }, - { post => 'prodrelations', required => 0, maxlength => 5000, default => '' }, - { post => 'editsum', required => !$nosubmit, template => 'editsum' }, - { post => 'ihid', required => 0 }, - { post => 'ilock', required => 0 }, - ); - $frm->{original} = '' if $frm->{original} eq $frm->{name}; - if(!$nosubmit && !$frm->{_err}) { - # parse - my $relations = [ map { /^([a-z]+),([0-9]+),(.+)$/ && (!$pid || $2 != $pid) ? [ $1, $2, $3 ] : () } split /\|\|\|/, $frm->{prodrelations} ]; - - # normalize - $frm->{ihid} = $frm->{ihid}?1:0; - $frm->{ilock} = $frm->{ilock}?1:0; - $frm->{desc} = $self->bbSubstLinks($frm->{desc}); - $relations = [] if $frm->{ihid}; - $frm->{prodrelations} = join '|||', map $_->[0].','.$_->[1].','.$_->[2], sort { $a->[1] <=> $b->[1]} @{$relations}; - - return $self->resRedirect("/p$pid", 'post') - if $pid && !grep +(($frm->{$_}//'') ne ($b4{$_}//'')), keys %b4; - - $frm->{relations} = $relations; - my $nrev = $self->dbItemEdit(p => $pid||undef, $pid ? $p->{rev} : undef, %$frm); - - # update reverse relations - if(!$pid && $#$relations >= 0 || $pid && $frm->{prodrelations} ne $b4{prodrelations}) { - my %old = $pid ? (map { $_->{id} => $_->{relation} } @{$p->{relations}}) : (); - my %new = map { $_->[1] => $_->[0] } @$relations; - _updreverse($self, \%old, \%new, $nrev->{itemid}, $nrev->{rev}); - } - - return $self->resRedirect("/p$nrev->{itemid}.$nrev->{rev}", 'post'); - } - } - - !defined $frm->{$_} && ($frm->{$_} = $b4{$_}) for keys %b4; - $frm->{lang} = 'ja' if !$pid && !defined $frm->{lang}; - $frm->{editsum} = sprintf 'Reverted to revision p%d.%d', $pid, $rev if $rev && !defined $frm->{editsum}; - - my $title = $pid ? "Edit $p->{name}" : 'Add new producer'; - $self->htmlHeader(title => $title, noindex => 1); - $self->htmlMainTabs('p', $p, 'edit') if $pid; - $self->htmlEditMessage('p', $p, $title); - $self->htmlForm({ frm => $frm, action => $pid ? "/old/p$pid/edit" : '/old/p/new', editsum => 1 }, - 'pedit_geninfo' => [ 'General info', - [ select => name => 'Type', short => 'type', - options => [ map [ $_, $PRODUCER_TYPE{$_} ], keys %PRODUCER_TYPE ] ], - [ input => name => 'Name (romaji)', short => 'name' ], - [ input => name => 'Original name', short => 'original' ], - [ static => content => 'The original name of the producer, leave blank if it is already in the Latin alphabet.' ], - [ textarea => short => 'alias', name => 'Aliases', rows => 4 ], - [ static => content => '(Un)official aliases, separated by a newline.' ], - [ select => name => 'Primary language', short => 'lang', - options => [ map [ $_, "$LANGUAGE{$_} ($_)" ], sort { $LANGUAGE{$a} cmp $LANGUAGE{$b} } keys %LANGUAGE ] ], - [ input => name => 'Website', short => 'website' ], - [ input => short => 'l_wikidata',name => 'Wikidata ID', - value => $frm->{l_wikidata} ? "Q$frm->{l_wikidata}" : '', - post => qq{ (<a href="$self->{url_static}/f/wikidata.png">How to find this</a>)} - ], - [ text => name => 'Description<br /><b class="standout">English please!</b>', short => 'desc', rows => 6 ], - ], 'pedit_rel' => [ 'Relations', - [ hidden => short => 'prodrelations' ], - [ static => nolabel => 1, content => sub { - h2 'Selected producers'; - table; - tbody id => 'relation_tbl'; - # to be filled using javascript - end; - end; - - h2 'Add producer'; - table; - Tr id => 'relation_new'; - td class => 'tc_prod'; - input type => 'text', class => 'text'; - end; - td class => 'tc_rel'; - Select; - option value => $_, $PRODUCER_RELATION{$_}{txt} - for (keys %PRODUCER_RELATION); - end; - end; - td class => 'tc_add'; - a href => '#', 'add'; - end; - end; - end 'table'; - }], - ]); - $self->htmlFooter; -} - -sub _updreverse { - my($self, $old, $new, $pid, $rev) = @_; - my %upd; - - # compare %old and %new - for (keys %$old, keys %$new) { - if(exists $$old{$_} and !exists $$new{$_}) { - $upd{$_} = undef; - } elsif((!exists $$old{$_} and exists $$new{$_}) || ($$old{$_} ne $$new{$_})) { - $upd{$_} = $PRODUCER_RELATION{$$new{$_}}{reverse}; - } - } - return if !keys %upd; - - # edit all related producers - for my $i (keys %upd) { - my $r = $self->dbProducerGetRev(id => $i, what => 'relations')->[0]; - my @newrel = map $_->{id} != $pid ? [ $_->{relation}, $_->{id} ] : (), @{$r->{relations}}; - push @newrel, [ $upd{$i}, $pid ] if $upd{$i}; - $self->dbItemEdit(p => $i, $r->{rev}, - relations => \@newrel, - editsum => "Reverse relation update caused by revision p$pid.$rev", - uid => 1, - ); - } -} - - sub list { my($self, $char) = @_; diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm index 72f32106..49d9441a 100644 --- a/lib/VNDB/Handler/Releases.pm +++ b/lib/VNDB/Handler/Releases.pm @@ -11,7 +11,6 @@ use VNDB::Types; TUWF::register( qr{r} => \&browse, qr{r/engines} => \&engines, - qr{xml/releases.xml} => \&relxml, qr{xml/engines.xml} => \&enginexml, ); @@ -164,30 +163,6 @@ sub engines { } -sub relxml { - my $self = shift; - - my $f = $self->formValidate( - { get => 'v', required => 1, multi => 1, mincount => 1, template => 'id' } - ); - return $self->resNotFound if $f->{_err}; - - my $vns = $self->dbVNGet(id => $f->{v}, order => 'title', results => 100); - my $rel = $self->dbReleaseGet(vid => $f->{v}, results => 100, what => 'vn'); - - $self->resHeader('Content-type' => 'text/xml; charset=UTF-8'); - xml; - tag 'vns'; - for my $v (@$vns) { - tag 'vn', id => $v->{id}, title => $v->{title}; - tag 'release', id => $_->{id}, lang => join(',', @{$_->{languages}}), $_->{title} - for (grep (grep $_->{vid} == $v->{id}, @{$_->{vn}}), @$rel); - end; - } - end; -} - - sub enginexml { my $self = shift; diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm index c052f726..85722f1b 100644 --- a/lib/VNDB/Util/CommonHTML.pm +++ b/lib/VNDB/Util/CommonHTML.pm @@ -3,16 +3,11 @@ package VNDB::Util::CommonHTML; use strict; use warnings; -use TUWF ':html', 'xml_escape', 'html_escape'; use Exporter 'import'; -use Algorithm::Diff::XS 'compact_diff'; -use Encode 'encode_utf8', 'decode_utf8'; use VNDB::Func; -use POSIX 'ceil'; our @EXPORT = qw| - htmlMainTabs htmlDenied htmlHiddenMessage htmlRevision - htmlEditMessage htmlItemMessage htmlSearchBox + htmlMainTabs htmlDenied htmlSearchBox |; @@ -31,189 +26,6 @@ sub htmlMainTabs { sub htmlDenied { shift->resDenied } -# Generates message saying that the current item has been deleted, -# Arguments: [pvrc], obj -# Returns 1 if the use doesn't have access to the page, 0 otherwise -sub htmlHiddenMessage { - my($self, $type, $obj) = @_; - return 0 if !$obj->{hidden}; - my $board = $type =~ /[csd]/ ? 'db' : $type eq 'r' ? 'v'.$obj->{vn}[0]{vid} : $type.$obj->{id}; - # fetch edit summary (not present in $obj, requires the db*GetRev() methods) - my $editsum = $type eq 'v' ? $self->dbVNGetRev(id => $obj->{id})->[0]{comments} - : $type eq 'r' ? $self->dbReleaseGetRev(id => $obj->{id})->[0]{comments} - : $type eq 'c' ? $self->dbCharGetRev(id => $obj->{id})->[0]{comments} - : $self->dbProducerGetRev(id => $obj->{id})->[0]{comments}; - div class => 'mainbox'; - h1 $obj->{title}||$obj->{name}; - div class => 'warning'; - h2 'Item deleted'; - p; - lit 'This item has been deleted from the database. File a request on the <a href="/t/'.$board.'">discussion board</a> to undelete this page.'; - br; br; - lit bb2html $editsum; - end; - end; - end 'div'; - return $self->htmlFooter() || 1 if !$self->authCan('dbmod'); - return 0; -} - - -# Shows a revision, including diff if there is a previous revision. -# Arguments: v|p|r|c|d, old revision, new revision, @fields -# Where @fields is a list of fields as arrayrefs with: -# [ shortname, displayname, %options ], -# Where %options: -# diff => 1/0/regex, whether to show a diff on this field, and what to split it with (1 = character-level diff) -# short_diff=> 1/0, when set, cut off long context in diffs -# serialize => coderef, should convert the field into a readable string, no HTML allowed -# htmlize => same as serialize, but HTML is allowed and this can't be diff'ed -# split => coderef, should return an array of HTML strings that can be diff'ed. (implies diff => 1) -# join => used in combination with split, specifies the string used for joining the HTML strings -sub htmlRevision { - my($self, $type, $old, $new, @fields) = @_; - div class => 'mainbox revision'; - h1 "Revision $new->{rev}"; - - # previous/next revision links - a class => 'prev', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}-1), '<- earlier revision' if $new->{rev} > 1; - a class => 'next', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}+1), 'later revision ->' if !$new->{lastrev}; - p class => 'center'; - a href => "/$type$new->{id}", "$type$new->{id}"; - end; - - # no previous revision, just show info about the revision itself - if(!$old) { - div class => 'rev'; - revheader($self, $type, $new); - br; - b 'Edit summary'; - br; br; - lit bb2html($new->{comments})||'-'; - end; - } - - # otherwise, compare the two revisions - else { - table class => 'stripe'; - thead; - Tr; - td; lit ' '; end; - td; revheader($self, $type, $old); end; - td; revheader($self, $type, $new); end; - end; - Tr; - td; lit ' '; end; - td colspan => 2; - b "Edit summary of revision $new->{rev}:"; - br; br; - lit bb2html($new->{comments})||'-'; - end; - end; - end; - revdiff($type, $old, $new, @$_) for ( - [ ihid => 'Deleted', serialize => sub { $_[0] ? 'Yes' : 'No' } ], - [ ilock => 'Locked', serialize => sub { $_[0] ? 'Yes' : 'No' } ], - @fields - ); - end 'table'; - } - end 'div'; -} - -sub revheader { # type, obj - my($self, $type, $obj) = @_; - b "Revision $obj->{rev}"; - txt ' ('; - a href => "/$type$obj->{id}.$obj->{rev}/edit", 'revert to'; - if($obj->{user_id} && $self->authCan('board')) { - lit ' / '; - a href => "/t/u$obj->{user_id}/new?title=Regarding%20$type$obj->{id}.$obj->{rev}", 'msg user'; - } - txt ')'; - br; - txt 'By '; - VNWeb::HTML::user_($obj); - txt ' on '; - txt fmtdate $obj->{added}, 'full'; -} - -sub revdiff { - my($type, $old, $new, $short, $display, %o) = @_; - - $o{serialize} ||= $o{htmlize}; - $o{diff} = 1 if $o{split}; - $o{join} ||= ''; - - my $ser1 = $o{serialize} ? $o{serialize}->($old->{$short}, $old) : $old->{$short}; - my $ser2 = $o{serialize} ? $o{serialize}->($new->{$short}, $new) : $new->{$short}; - return if $ser1 eq $ser2; - - if($o{diff} && $ser1 && $ser2) { - my $sep = ref $o{diff} ? qr/($o{diff})/ : qr//; - my @ser1 = map encode_utf8($_), $o{split} ? $o{split}->($ser1) : map html_escape($_), split $sep, $ser1; - my @ser2 = map encode_utf8($_), $o{split} ? $o{split}->($ser2) : map html_escape($_), split $sep, $ser2; - return if $o{split} && $#ser1 == $#ser2 && !grep $ser1[$_] ne $ser2[$_], 0..$#ser1; - - $ser1 = $ser2 = ''; - my @d = compact_diff(\@ser1, \@ser2); - my $lastchunk = int (($#d-2)/2); - for my $i (0..$lastchunk) { - # $i % 2 == 0 -> equal, otherwise it's different - my $a = join($o{join}, @ser1[ $d[$i*2] .. $d[$i*2+2]-1 ]); - my $b = join($o{join}, @ser2[ $d[$i*2+1] .. $d[$i*2+3]-1 ]); - # Reduce context if we have too much - if($o{short_diff} && $i % 2 == 0 && length($a) > 300) { - my $sep = '<b class="standout"><...></b>'; - my $ctx = 100; - $a = $i == 0 ? $sep.'<br>'.substr $a, -$ctx : - $i == $lastchunk ? substr($a, 0, $ctx).'<br>'.$sep : - substr($a, 0, $ctx)."<br><br>$sep<br><br>".substr($a, -$ctx); - $b = $a; - } - $ser1 .= ($ser1?$o{join}:'').($i % 2 ? qq|<b class="diff_del">$a</b>| : $a) if $a ne ''; - $ser2 .= ($ser2?$o{join}:'').($i % 2 ? qq|<b class="diff_add">$b</b>| : $b) if $b ne ''; - } - $ser1 = decode_utf8($ser1); - $ser2 = decode_utf8($ser2); - } elsif(!$o{htmlize}) { - $ser1 = html_escape $ser1; - $ser2 = html_escape $ser2; - } - - $ser1 = '[empty]' if !$ser1 && $ser1 ne '0'; - $ser2 = '[empty]' if !$ser2 && $ser2 ne '0'; - - Tr; - td $display; - td class => 'tcval'; lit $ser1; end; - td class => 'tcval'; lit $ser2; end; - end; -} - - -# Generates a generic message to show as the header of the edit forms -# Arguments: v/r/p, obj, title, copy -sub htmlEditMessage { - shift; VNWeb::HTML::editmsg_(@_); -} - - -# Generates a small message when the user can't edit the item, -# or the item is locked. -# Arguments: v/r/p/c, obj -sub htmlItemMessage { - my($self, $type, $obj) = @_; - # $type isn't being used at all... oh well. - - if($obj->{locked}) { - p class => 'locked', 'Locked for editing'; - } elsif($self->authInfo->{id} && !$self->authCan('edit')) { - p class => 'locked', 'You are not allowed to edit this page'; - } -} - - sub htmlSearchBox { shift; VNWeb::HTML::searchbox_(@_); } |