summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Makefile7
-rw-r--r--data/docs/73
-rw-r--r--data/global.pl4
-rw-r--r--data/lang.txt377
-rw-r--r--data/script.js173
-rw-r--r--data/style.css4
-rw-r--r--lib/Multi/Feed.pm6
-rw-r--r--lib/Multi/Maintenance.pm4
-rw-r--r--lib/VNDB/DB/Chars.pm22
-rw-r--r--lib/VNDB/DB/VN.pm6
-rw-r--r--lib/VNDB/Handler/Chars.pm20
-rw-r--r--lib/VNDB/Handler/Producers.pm2
-rw-r--r--lib/VNDB/Handler/Releases.pm4
-rw-r--r--lib/VNDB/Handler/Tags.pm6
-rw-r--r--lib/VNDB/Handler/Traits.pm15
-rw-r--r--lib/VNDB/Handler/VNEdit.pm78
-rw-r--r--lib/VNDB/Util/CommonHTML.pm2
-rw-r--r--lib/VNDB/Util/FormHTML.pm17
-rw-r--r--lib/VNDB/Util/LayoutHTML.pm2
-rw-r--r--lib/VNDB/Util/Misc.pm5
-rwxr-xr-xutil/jsgen.pl3
-rw-r--r--util/sql/all.sql3
-rw-r--r--util/sql/func.sql14
-rw-r--r--util/updates/update_2.22.sql11
25 files changed, 580 insertions, 215 deletions
diff --git a/ChangeLog b/ChangeLog
index 3cc9200c..c33d1b92 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,9 @@
-2.22 - ?
+2.22 - 2011-12-31
+ - Added character filters
+ - Added duplicate checking form before creating a new VN entry
+ - Combined "remove" and "add" labels in a single lang.txt entry
+ - Added secondary order to VN browser when sorting on release date
+ - doc updates for the characters and traits
2.21 - 2011-08-23
- New resolution: 1280x960
diff --git a/Makefile b/Makefile
index 632e2e70..45685557 100644
--- a/Makefile
+++ b/Makefile
@@ -39,7 +39,7 @@
.PHONY: all dirs js skins robots chmod chmod-tladmin multi-stop multi-start multi-restart sql-import\
update-2.10 update-2.11 update-2.12 update-2.13 update-2.14 update-2.15 update-2.16 update-2.17\
- update-2.18 update-2.19 update-2.20 update-2.21
+ update-2.18 update-2.19 update-2.20 update-2.21 update-2.22
all: dirs js skins robots data/config.pl
@@ -190,3 +190,8 @@ update-2.21: all
${runpsql} < util/updates/update_2.21.sql
$(multi-start)
+update-2.22: all
+ $(multi-stop)
+ ${runpsql} < util/updates/update_2.22.sql
+ $(multi-start)
+
diff --git a/data/docs/7 b/data/docs/7
index 7a8e2d83..058075fd 100644
--- a/data/docs/7
+++ b/data/docs/7
@@ -50,7 +50,8 @@
<b>Code development</b><br />
<dl>
<dt>Yorhel</dt><dd>Main developer.</dd>
- <dt>3dB</dt><dd>Wrote the current user authentication code and implemented post throttling on the discussion board.</dd>
+ <dt>QCyph</dt><dd>Contributed the character filters.</dd>
+ <dt>3dB</dt><dd>Contributed the current user authentication code and post throttling on the discussion board.</dd>
</dl>
<br />
diff --git a/data/global.pl b/data/global.pl
index 31d45631..fd9c3e31 100644
--- a/data/global.pl
+++ b/data/global.pl
@@ -31,8 +31,8 @@ our %S = (%S,
scr_size => [ 136, 102 ], # w*h of screenshot thumbnails
ch_size => [ 256, 300 ], # max. w*h of char images
cv_size => [ 256, 400 ], # max. w*h of cover images
- # bit flags
- permissions => {qw| board 1 boardmod 2 edit 4 charedit 8 tag 16 dbmod 32 tagmod 64 usermod 128 affiliate 256 |},
+ # bit flags (TODO: completely merge charedit into edit)
+ permissions => {qw| board 1 boardmod 2 edit 4 charedit 4 tag 16 dbmod 32 tagmod 64 usermod 128 affiliate 256 |},
languages => [qw|cs da de en es fi fr hu it ja ko nl no pl pt-br pt-pt ru sk sv tr vi zh|],
producer_types => [qw|co in ng|],
discussion_boards => [qw|an db ge v p u|], # <- note that some properties of these boards are hard-coded
diff --git a/data/lang.txt b/data/lang.txt
index 03c7b132..a453fc48 100644
--- a/data/lang.txt
+++ b/data/lang.txt
@@ -1641,6 +1641,22 @@ hu : Beküldés
nl : Verstuur
de : Bestätigen
+:_form_continue
+en : Continue
+ru*:
+cs*:
+hu*:
+nl : Verder
+de*:
+
+:_form_continue_ign
+en : Continue and ignore duplicates
+ru*:
+cs*:
+hu*:
+nl : Ga verder en negeer dubbele items
+de*:
+
:_form_ihid
en : Deleted
ru : Удалено
@@ -1724,6 +1740,22 @@ hu : -nap-
nl : -dag-
de : -Tag-
+:_js_remove
+en : remove
+ru : убрать
+cs : odstranit
+hu : eltávolítás
+nl : verwijder
+de : entfernen
+
+:_js_add
+en : add
+ru : добавить
+cs : přidat
+hu : bejegyez
+nl : toevoegen
+de : hinzufügen
+
:_js_ds_noresults
en : No results...
ru : Совпадений не найдено...
@@ -1772,6 +1804,30 @@ hu : Itt nem használhatsz meta címkéket!
nl : Meta tags kunnen hier niet gebruikt worden!
de : Meta-Tags können hier nicht genutzt werden!
+:_js_ds_trait_meta
+en : meta
+ru*:
+cs*:
+hu*:
+nl :
+de*:
+
+:_js_ds_trait_mod
+en : awaiting moderation
+ru*:
+cs*:
+hu*:
+nl : ongemodereerd
+de*:
+
+:_js_ds_trait_nometa
+en : Can't use meta traits here!
+ru*:
+cs*:
+hu*:
+nl : Meta kenmerken kunnen hier niet gebruikt worden!
+de*:
+
# Filter selector
@@ -2354,15 +2410,6 @@ hu : szerkesztés
nl : wijzig
de : bearbeiten
-# delete
-:_mtabs_del
-en : del
-ru : удалить
-cs : smazat
-hu : törlés
-nl : verwijder
-de : löschen
-
# VN relations
:_mtabs_relations
en : relations
@@ -3494,22 +3541,6 @@ hu : Készítő bejegyzése
nl : Nieuwe producent toevoegen
de : Hersteller hinzufügen
-:_pedit_rel_addbut
-en : add
-ru : добавить
-cs : přidat
-hu : hozzáad
-nl : toevoegen
-de : hinzufügen
-
-:_pedit_rel_del
-en : remove
-ru : убрать
-cs : odebrat
-hu : eltávolít
-nl : verwijderen
-de : entfernen
-
:_pedit_rel_none
en : Nothing selected.
ru : Ничего не выбрано.
@@ -4256,14 +4287,6 @@ hu : -medium-
nl :
de : -Medium-
-:_redit_form_med_remove
-en : remove
-ru : убрать
-cs : odebrat
-hu : eltávolítás
-nl : verwijder
-de : entfernen
-
:_redit_form_prod
en : Producers
ru : Компании
@@ -4312,22 +4335,6 @@ hu : Mindkettő
nl : Beide
de : Beides
-:_redit_form_prod_addbut
-en : add
-ru : добавить
-cs : přidat
-hu : bejegyez
-nl : voeg toe
-de : hinzufügen
-
-:_redit_form_prod_remove
-en : remove
-ru : убрать
-cs : odebrat
-hu : eltávolít
-nl : verwijder
-de : entfernen
-
:_redit_form_prod_none
en : Nothing selected.
ru : Ничего не выбрано.
@@ -4384,22 +4391,6 @@ hu : Visual novel bejegyzése
nl : Nieuwe visual novel
de : Visual Novel hinzufügen
-:_redit_form_vn_addbut
-en : add
-ru : добавить
-cs : přidat
-hu : bejegyez
-nl : voeg toe
-de : hinzufügen
-
-:_redit_form_vn_remove
-en : remove
-ru : убрать
-cs : odebrat
-hu : eltávolít
-nl : verwijder
-de : entfernen
-
:_redit_form_vn_none
en : Nothing selected.
ru : Ничего не выбрано.
@@ -5268,14 +5259,6 @@ hu : Aktív szűrők:
nl : Actieve filters:
de : Aktive Filter:
-:_taglink_fil_remove
-en : remove
-ru : убрать
-cs : odstranit
-hu : eltávolít
-nl : verwijder
-de : entfernen
-
:_taglink_fil_user
en : User:
ru : Пользователь:
@@ -6171,14 +6154,6 @@ hu : Sajátosság hozzáadása
nl : Voeg kenmerk toe
de : Füge Eigenschaft hinzu
-:_chare_traits_del
-en : del
-ru*:
-cs*:
-hu : töröl
-nl :
-de : entfernen
-
:_chare_traits_present
en : Selected trait is already present.
ru*:
@@ -6251,14 +6226,6 @@ hu : Mind / mások
nl : Alle / overige
de : Alle / andere
-:_chare_vns_del
-en : remove
-ru*:
-cs : odstranit
-hu : eltávolít
-nl : verwijder
-de : entfernen
-
:_chare_vns_allrel
en : All releases already selected.
ru*:
@@ -6310,8 +6277,181 @@ hu : A kritériumaid alapján nem található szereplő.
nl : Geen karakters gevonden die aan je kriteria voldoen.
de : Keine Charaktere, die deinen Kriterien entsprechen, gefunden.
+:_charb_fil_title
+en : Character filters
+ru*:
+cs*:
+hu*:
+nl : Karakterfilters
+de*:
+
+:_charb_general
+en : General
+ru*:
+cs*:
+hu*:
+nl : Algemeen
+de*:
+
+:_charb_gender
+en : Gender
+ru*:
+cs*:
+hu*:
+nl : Geslacht
+de*:
+
+:_charb_bust_min
+en : Bust min
+ru*:
+cs*:
+hu*:
+nl : Borst min
+de*:
+
+:_charb_bust_max
+en : Bust max
+ru*:
+cs*:
+hu*:
+nl : Borst max
+de*:
+
+:_charb_waist_min
+en : Waist min
+ru*:
+cs*:
+hu*:
+nl : Taille min
+de*:
+
+:_charb_waist_max
+en : Waist max
+ru*:
+cs*:
+hu*:
+nl : Taille max
+de*:
+
+:_charb_hip_min
+en : Hips min
+ru*:
+cs*:
+hu*:
+nl : Heupen min
+de*:
+
+:_charb_hip_max
+en : Hips max
+ru*:
+cs*:
+hu*:
+nl : Heupen max
+de*:
+
+:_charb_height_min
+en : Height min
+ru*:
+cs*:
+hu*:
+nl : Lengte min
+de*:
+
+:_charb_height_max
+en : Height max
+ru*:
+cs*:
+hu*:
+nl : Lengte max
+de*:
+
+:_charb_weight_min
+en : Weight min
+ru*:
+cs*:
+hu*:
+nl : Gewicht min
+de*:
+
+:_charb_weight_max
+en : Weight max
+ru*:
+cs*:
+hu*:
+nl : Gewicht max
+de*:
+
+:_charb_bloodt
+en : Blood type
+ru*:
+cs*:
+hu*:
+nl : Bloedgroep
+de*:
+
+:_charb_traits
+en : Traits
+ru*:
+cs*:
+hu*:
+nl : Kenmerken
+de*:
+
+:_charb_traitinc
+en : Traits to include
+ru*:
+cs*:
+hu*:
+nl : Kenmerken meenemen
+de*:
+
+:_charb_traitexc
+en : Traits to exclude
+ru*:
+cs*:
+hu*:
+nl : Kenmerken uitsluiten
+de*:
+:_charb_traitnothere
+en : Additional trait filters are not available on this page. Use the character browser instead (available from the main menu -> characters).
+ru*:
+cs*:
+hu*:
+nl : Extra kenmerkfilters zijn niet aanwezig op deze pagina. Gebruik de karakterbrowser voor deze functionaliteit (beschikbaar via het hoofdmenu -> karakters).
+de*:
+:_charb_spoil0
+en : Hide spoilers
+ru*:
+cs*:
+hu*:
+nl : Verberg spoilers
+de*:
+
+:_charb_spoil1
+en : Show minor spoilers
+ru*:
+cs*:
+hu*:
+nl : Toon geringe spoilers
+de*:
+
+:_charb_spoil2
+en : Show major spoilers
+ru*:
+cs*:
+hu*:
+nl : Toon alle spoilers
+de*:
+
+:_charb_roles
+en : Roles
+ru*:
+cs*:
+hu*:
+nl : Rol
+de*:
@@ -8112,14 +8252,6 @@ hu : Ezzek a szűrők figyelmen kívűl maradnak a címke oldalakon (ha alapért
nl : Deze filters worden genegeerd op tagpaginas (als ze gebruikt worden als standaardfilters).
de : Diese Filter werden auf Tag-Seiten ignoriert (wenn als Standard eingestellt).
-:_vnbrowse_tagrem
-en : remove
-ru : убрать
-cs : odstranit
-hu : eltávolítás
-nl : verwijder
-de : entfernen
-
:_vnbrowse_taginc
en : Tags to include
ru : Включить теги
@@ -8299,6 +8431,33 @@ hu : Új visual novel bejegyzése
nl : Voeg nieuwe visual novel toe
de : Neue Visual Novel hinzufügen
+:_vnedit_dup_title
+en : Possible duplicates found
+ru*:
+cs*:
+hu*:
+nl : Mogelijke dubbele items gevonden
+de*:
+
+:_vnedit_dup_msg
+en : The following is a list of visual novels that match the title(s) you gave.
+ Please check this list to avoid creating a duplicate visual novel entry.
+ Be especially wary of items that have been deleted! To see why an entry
+ has been deleted, click on its title.[br]
+ [br]
+ To add the visual novel either way, hit the "Continue and ignore
+ duplicates" button below.
+ru*:
+cs*:
+hu*:
+nl : De onderstaande lijst bevat visual novels met een vergelijkbare titel.
+ Controleer deze lijst a.u.b. om te voorkomen dat je een visual novel dubbel toevoegt.
+ Wees helemaal op de hoede van items die verwijderd zijn! Om te zien waarom
+ iets verwijderd is, klik op de titel.[br]
+ [br]
+ Klik op de "Ga verder en negeer dubbele items" knop om alsnog verder te gaan.
+de*:
+
:_vnedit_geninfo
en : General info
ru : Основная информация
@@ -8577,22 +8736,6 @@ hu : -
nl : van
de : von
-:_vnedit_rel_addbut
-en : add
-ru : добавить
-cs : přidat
-hu : bejegyez
-nl : toevoegen
-de : hinzufügen
-
-:_vnedit_rel_del
-en : del
-ru : убрать
-cs : smazat
-hu : töröl
-nl : verwijder
-de : entfernen
-
:_vnedit_rel_none
en : No relations selected.
ru : Отношений не выбрано.
@@ -8789,14 +8932,6 @@ hu : #[_1]-dik pillanatkép
nl :
de : Screenshot #[_1]
-:_vnedit_scr_remove
-en : remove
-ru : убрать
-cs : odebrat
-hu : eltávolítás
-nl : verwijder
-de : entfernen
-
:_vnedit_scr_fullsize
en : Full size: [_1]
ru : Полный размер: [_1]
diff --git a/data/script.js b/data/script.js
index e85bce3d..4065def4 100644
--- a/data/script.js
+++ b/data/script.js
@@ -819,7 +819,7 @@ function vnrAdd(rel, vid, official, title) {
tag('label', {'for':'official_'+vid}, mt('_vnedit_rel_official')),
sel, ' '+mt('_vnedit_rel_of')),
tag('td', {'class':'tc_title'}, shorten(byId('title').value, 40)),
- tag('td', {'class':'tc_add' }, tag('a', {href:'#', onclick:vnrDel}, mt('_vnedit_rel_del')))
+ tag('td', {'class':'tc_add' }, tag('a', {href:'#', onclick:vnrDel}, mt('_js_remove')))
));
vnrEmpty();
@@ -880,7 +880,7 @@ function vnrFormAdd() {
ajax('/xml/vn.xml?q='+encodeURIComponent(input), function(hr) {
txt.disabled = sel.disabled = off.disabled = false;
txt.value = '';
- setText(lnk, mt('_vnedit_rel_addbut'));
+ setText(lnk, mt('_js_add'));
var items = hr.responseXML.getElementsByTagName('item');
if(items.length < 1)
@@ -933,7 +933,7 @@ function medAdd(med, qty) {
msel.appendChild(tag('option', {value:medTypes[i][0], selected: med==medTypes[i][0]}, medTypes[i][1]));
byId('media_div').appendChild(tag('span', qsel, msel,
- med != '' ? tag('input', {type: 'button', 'class':'submit', onclick:medDel, value:mt('_redit_form_med_remove')}) : null
+ med != '' ? tag('input', {type: 'button', 'class':'submit', onclick:medDel, value:mt('_js_remove')}) : null
));
}
@@ -1148,7 +1148,7 @@ function scrCheckStatus() {
var nsfwid = 'scr_sfw_'+tr.scr_id;
setContent(byName(tr, 'td')[1],
tag('b', mt('_vnedit_scr_id', tr.scr_id)),
- ' (', tag('a', {href: '#', onclick:scrDel}, mt('_vnedit_scr_remove')), ')',
+ ' (', tag('a', {href: '#', onclick:scrDel}, mt('_js_remove')), ')',
tag('br', null),
mt('_vnedit_scr_fullsize', dim),
odd ? tag('b', {'class':'standout', 'style':'font-weight: bold'}, ' '+mt('_vnedit_scr_nonstandard')) : null,
@@ -1454,7 +1454,7 @@ function rvnLoad() {
function rvnAdd(id, title) {
byId('vn_tbl').appendChild(tag('tr', {id:'rvn_'+id, rvn_id:id},
tag('td', {'class':'tc_title'}, 'v'+id+':', tag('a', {href:'/v'+id}, shorten(title, 40))),
- tag('td', {'class':'tc_rm'}, tag('a', {href:'#', onclick:rvnDel}, mt('_redit_form_vn_remove')))
+ tag('td', {'class':'tc_rm'}, tag('a', {href:'#', onclick:rvnDel}, mt('_js_remove')))
));
rvnStripe();
rvnEmpty();
@@ -1502,7 +1502,7 @@ function rvnFormAdd() {
ajax('/xml/vn.xml?q='+encodeURIComponent(val), function(hr) {
txt.disabled = false;
txt.value = '';
- setText(lnk, mt('_redit_form_vn_addbut'));
+ setText(lnk, mt('_js_add'));
var items = hr.responseXML.getElementsByTagName('item');
if(items.length < 1)
@@ -1564,7 +1564,7 @@ function rprAdd(id, role, name) {
byId('producer_tbl').appendChild(tag('tr', {id:'rpr_'+id, rpr_id:id},
tag('td', {'class':'tc_name'}, 'p'+id+':', tag('a', {href:'/p'+id}, shorten(name, 40))),
tag('td', {'class':'tc_role'}, rl),
- tag('td', {'class':'tc_rm'}, tag('a', {href:'#', onclick:rprDel}, mt('_redit_form_prod_remove')))
+ tag('td', {'class':'tc_rm'}, tag('a', {href:'#', onclick:rprDel}, mt('_js_remove')))
));
rprEmpty();
}
@@ -1604,7 +1604,7 @@ function rprFormAdd() {
ajax('/xml/producers.xml?q='+encodeURIComponent(val), function(hr) {
txt.disabled = false;
txt.value = '';
- setText(lnk, mt('_redit_form_prod_addbut'));
+ setText(lnk, mt('_js_add'));
var items = hr.responseXML.getElementsByTagName('item');
if(items.length < 1)
@@ -1676,7 +1676,7 @@ function prrAdd(rel, pid, title) {
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}, mt('_pedit_rel_del')))
+ tag('td', {'class':'tc_add' }, tag('a', {href:'#', onclick:prrDel}, mt('_js_remove')))
));
prrEmpty();
@@ -1735,7 +1735,7 @@ function prrFormAdd() {
ajax('/xml/producers.xml?q='+encodeURIComponent(input), function(hr) {
txt.disabled = sel.disabled = false;
txt.value = '';
- setText(lnk, mt('_pedit_rel_addbut'));
+ setText(lnk, mt('_js_add'));
var items = hr.responseXML.getElementsByTagName('item');
if(items.length < 1)
@@ -1818,7 +1818,7 @@ function ctrAdd(item, spoil) {
tag('b', {'class':'grayedout'}, group?group+' / ':''),
tag('a', {'href':'/i'+id}, name)),
sp,
- tag('td', {'class':'tc_del'}, tag('a', {href:'#', onclick:ctrDel}, mt('_chare_traits_del')))
+ tag('td', {'class':'tc_del'}, tag('a', {href:'#', onclick:ctrDel}, mt('_js_remove')))
));
ctrEmpty();
ctrSerialize();
@@ -1988,7 +1988,7 @@ function cvnRelAdd(vid, rid, role, spoil) {
tag('td', {'class':'tc_rel'}, rsel),
tag('td', {'class':'tc_rol'}, lsel),
tag('td', {'class':'tc_spl'}, ssel),
- tag('td', {'class':'tc_del'}, tag('a', {href:'#', onclick:cvnRelDel}, mt('_chare_vns_del')))
+ tag('td', {'class':'tc_del'}, tag('a', {href:'#', onclick:cvnRelDel}, mt('_js_remove')))
), last);
}
@@ -2124,7 +2124,9 @@ if(byId('jt_box_chare_vns'))
var fil_cats; // [ <object with field->tr mapping>, <category-link1>, .. ]
var fil_escape = "_ !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~".split('');
function filLoad() {
- var l = byId('filselect').href.match(/#r$/) ? filReleases() : filVN();
+ var l = byId('filselect').href.match(/#r$/) ? filReleases()
+ : byId('filselect').href.match(/#c$/) ? filChars()
+ : filVN();
fil_cats = [ new Object ];
var p = tag('p', {'class':'browseopts'});
@@ -2179,7 +2181,8 @@ function filLoad() {
f.submit();
}}),
tag('input', {type:'button', 'class':'submit', value: mt('_js_fil_reset'), onclick:function () { byId('fil').value = ''; filDeSerialize()} }),
- PREF_CODE != '' ? tag('input', {type:'button', 'class':'submit', value: mt('_js_fil_save'), onclick:filSaveDefault }) : null,
+ typeof PREFS != 'undefined' && ('filter_vn' in PREFS | 'filter_release' in PREFS) && PREF_CODE != '' ?
+ tag('input', {type:'button', 'class':'submit', value: mt('_js_fil_save'), onclick:filSaveDefault }) : null,
tag('p', {id:'fil_savenote', 'class':'hidden'}, '')
));
filSelectCat(1);
@@ -2265,7 +2268,7 @@ function filSerialize() {
if(r.length > 0 && r[0] != '')
values[fil_cats[0][f].fil_code] = r.join('~');
}
- if(!values['tag_inc'])
+ if(!values['tag_inc'] && !values['trait_inc'])
delete values['tagspoil'];
var l = [];
for(var f in values)
@@ -2323,6 +2326,63 @@ function filShow() {
return false;
}
+var curSlider = null;
+function filFSlider(c, n, min, max, def, unit) {
+ var bw = 200; var pw = 1; // slidebar width and pointer width
+ var s = tag('p', {fil_val:def, 'class':'slider'});
+ var b = tag('div', {style:'width:'+(bw-2)+'px;', s:s});
+ var p = tag('div', {style:'width:'+pw+'px;', s:s});
+ var v = tag('span', def+' '+unit);
+ s.appendChild(b);
+ b.appendChild(p);
+ s.appendChild(v);
+
+ var set = function (e, v) {
+ var w = bw-pw-6;
+ var s,x;
+
+ if(v) {
+ s = e;
+ x = v[0] == '' ? def : parseInt(v[0]);
+ x = (x-min)*w/(max-min);
+ } else {
+ s = curSlider;
+ if(!e) e = window.event;
+ x = (!e) ? (def-min)*w/(max-min)
+ : (e.pageX || e.clientX + document.body.scrollLeft - document.body.clientLeft)-5;
+ var o = s.childNodes[0];
+ while(o.offsetParent) {
+ x -= o.offsetLeft;
+ o = o.offsetParent;
+ }
+ }
+
+ if(x<0) x = 0; if(x>w) x = w;
+ s.fil_val = min + Math.floor(x*(max-min)/w);
+ s.childNodes[1].innerHTML = s.fil_val+' '+unit;
+ s.childNodes[0].childNodes[0].style.left = x+'px';
+ return false;
+ }
+
+ b.onmousedown = p.onmousedown = function (e) {
+ curSlider = this.s;
+ if(!curSlider.oldmousemove) curSlider.oldmousemove = document.onmousemove;
+ if(!curSlider.oldmouseup) curSlider.oldmouseup = document.onmouseup;
+ document.onmouseup = function () {
+ document.onmousemove = curSlider.oldmousemove;
+ curSlider.oldmousemove = null;
+ document.onmouseup = curSlider.oldmouseup;
+ curSlider.oldmouseup = null;
+ filSelectField(curSlider);
+ return false;
+ }
+ document.onmousemove = set;
+ return set(e);
+ }
+
+ return [c, n, s, function (c) { return [ c.fil_val ]; }, set ];
+}
+
function filFSelect(c, n, lines, opts) {
var s = tag('select', {onfocus: filSelectField, onchange: filSerialize, multiple: lines > 1, size: lines});
for(var i=0; i<opts.length; i++) {
@@ -2379,14 +2439,18 @@ function filFOptions(c, n, opts, setfunc) {
];
}
-function filFTagInput(name, label) {
+function filFTagInput(name, label, type) {
+ var src = type=='tag' ? '/xml/tags.xml' : '/xml/traits.xml';
+
var visible = false;
var remove = function() {
;
};
- var addtag = function(ul, id, name) {
- ul.appendChild(tag('li', { fil_id: id },
- tag('a', {href:'/g'+id}, name||'g'+id),
+ var addtag = function(ul, id, name, group) {
+ ul.appendChild(
+ tag('li', { fil_id: id },
+ type=='trait' && group ? tag('b', {'class':'grayedout'}, group+' / ') : null,
+ type=='tag' ? tag('a', {href:'/g'+id}, name||'g'+id) : tag('a', {href:'/i'+id}, name||'i'+id),
' (', tag('a', {href:'#',
onclick:function () {
// a -> li -> ul -> div
@@ -2395,7 +2459,7 @@ function filFTagInput(name, label) {
filSelectField(ul.parentNode);
return false
}
- }, mt('_vnbrowse_tagrem')), ')'
+ }, mt('_js_remove')), ')'
));
}
var fetch = function(c) {
@@ -2421,12 +2485,12 @@ function filFTagInput(name, label) {
txt.value = mt('_js_loading');
txt.disabled = true;
if(visible)
- ajax('/xml/tags.xml?'+q.join(';'), function (hr) {
+ ajax(src+'?'+q.join(';'), function (hr) {
var l = [];
var items = hr.responseXML.getElementsByTagName('item');
setText(ul, '');
for(var i=0; i<items.length; i++)
- addtag(ul, items[i].getAttribute('id'), items[i].firstChild.nodeValue);
+ addtag(ul, items[i].getAttribute('id'), items[i].firstChild.nodeValue, items[i].getAttribute('groupname'));
txt.value = '';
txt.disabled = false;
c.fil_val = null;
@@ -2434,18 +2498,21 @@ function filFTagInput(name, label) {
};
var input = tag('input', {type:'text', 'class':'text', style:'width:300px', onfocus:filSelectField});
var list = tag('ul', null);
- dsInit(input, '/xml/tags.xml?q=',
+ dsInit(input, src+'?q=',
function(item, tr) {
- tr.appendChild(tag('td', shorten(item.firstChild.nodeValue, 40),
- item.getAttribute('meta') == 'yes' ? tag('b', {'class': 'grayedout'}, ' '+mt('_js_ds_tag_meta')) : null,
- item.getAttribute('state') == 0 ? tag('b', {'class': 'grayedout'}, ' '+mt('_js_ds_tag_mod')) : null
+ var g = item.getAttribute('groupname');
+ tr.appendChild(tag('td',
+ type=='trait' && g ? tag('b', {'class':'grayedout'}, g+' / ') : null,
+ shorten(item.firstChild.nodeValue, 40), // l10n /_js_ds_(tag|trait)_(meta|mod)/
+ item.getAttribute('meta') == 'yes' ? tag('b', {'class': 'grayedout'}, ' '+mt('_js_ds_'+type+'_meta')) : null,
+ item.getAttribute('state') == 0 ? tag('b', {'class': 'grayedout'}, ' '+mt('_js_ds_'+type+'_mod')) : null
));
},
function(item, obj) {
- if(item.getAttribute('meta') == 'yes')
- alert(mt('_js_ds_tag_nometa'));
+ if(item.getAttribute('meta') == 'yes') // l10n /_js_ds_(tag|trait)_nometa/
+ alert(mt('_js_ds_'+type+'_nometa'));
else {
- addtag(byName(obj.parentNode, 'ul')[0], item.getAttribute('id'), item.firstChild.nodeValue);
+ addtag(byName(obj.parentNode, 'ul')[0], item.getAttribute('id'), item.firstChild.nodeValue, item.getAttribute('groupname'));
filSelectField(obj);
}
return '';
@@ -2466,6 +2533,50 @@ function filFTagInput(name, label) {
];
}
+function filChars() {
+ var gend = genders;
+ for(var i=0; i<gend.length; i++) // l10n /_gender_.+/
+ gend[i] = [ gend[i], mt('_gender_'+gend[i]) ];
+ var bloodt = blood_types;
+ for(var i=0; i<bloodt.length; i++) // l10n /_bloodt_.+/
+ bloodt[i] = [ bloodt[i], mt('_bloodt_'+bloodt[i]) ];
+ var roles = char_roles;
+ for(var i=0; i<roles.length; i++) // l10n /_charrole_.+/
+ roles[i] = [ roles[i], mt('_charrole_'+roles[i]) ];
+
+ var ontraitpage = location.pathname.indexOf('/c/') < 0;
+
+ return [
+ mt('_charb_fil_title'),
+ [ mt('_charb_general'),
+ filFSelect('gender', mt('_charb_gender'), 4, gend),
+ filFSelect('bloodt', mt('_charb_bloodt'), 5, bloodt),
+ '',
+ filFSlider('bust_min', mt('_charb_bust_min'), 20, 120, 40, 'cm'),
+ filFSlider('bust_max', mt('_charb_bust_max'), 20, 120, 100, 'cm'),
+ filFSlider('waist_min', mt('_charb_waist_min'), 20, 120, 40, 'cm'),
+ filFSlider('waist_max', mt('_charb_waist_max'), 20, 120, 100, 'cm'),
+ filFSlider('hip_min', mt('_charb_hip_min'), 20, 120, 40, 'cm'),
+ filFSlider('hip_max', mt('_charb_hip_max'), 20, 120, 100, 'cm'),
+ '',
+ filFSlider('height_min', mt('_charb_height_min'), 0, 300, 60, 'cm'),
+ filFSlider('height_max', mt('_charb_height_max'), 0, 300, 240, 'cm'),
+ filFSlider('weight_min', mt('_charb_weight_min'), 0, 400, 80, 'kg'),
+ filFSlider('weight_max', mt('_charb_weight_max'), 0, 400, 320, 'kg'),
+ ],
+ ontraitpage ? [ mt('_charb_traits'),
+ [ '', ' ', tag(mt('_charb_traitnothere')) ],
+ ] : [ mt('_charb_traits'),
+ [ '', ' ', tag(mt('_js_fil_booland')) ],
+ filFTagInput('trait_inc', mt('_charb_traitinc'), 'trait'),
+ filFTagInput('trait_exc', mt('_charb_traitexc'), 'trait'),
+ filFOptions('tagspoil', ' ', [[0, mt('_charb_spoil0')],[1, mt('_charb_spoil1')],[2, mt('_charb_spoil2')]],
+ function (o) { var s = getCookie('tagspoil'); if(o+'' == '') return s == null ? 0 : s; setCookie('tagspoil', o); return o})
+ ],
+ [ mt('_charb_roles'), filFSelect('role', mt('_charb_roles'), 4, roles) ]
+ ];
+}
+
function filReleases() {
var types = release_types;
for(var i=0; i<types.length; i++) // l10n /_rtype_.+/
@@ -2537,8 +2648,8 @@ function filVN() {
] : [ mt('_vnbrowse_tags'),
[ '', ' ', tag(mt('_js_fil_booland')) ],
[ '', ' ', PREF_CODE != '' ? tag(mt('_vnbrowse_tagactive')) : null ],
- filFTagInput('tag_inc', mt('_vnbrowse_taginc')),
- filFTagInput('tag_exc', mt('_vnbrowse_tagexc')),
+ filFTagInput('tag_inc', mt('_vnbrowse_taginc'), 'tag'),
+ filFTagInput('tag_exc', mt('_vnbrowse_tagexc'), 'tag'),
filFOptions('tagspoil', ' ', [[0, mt('_vnbrowse_spoil0')],[1, mt('_vnbrowse_spoil1')],[2, mt('_vnbrowse_spoil2')]],
function (o) { var s = getCookie('tagspoil'); if(o+'' == '') return s == null ? 0 : s; setCookie('tagspoil', o); return o})
],
diff --git a/data/style.css b/data/style.css
index 78f3736f..ecb8bb42 100644
--- a/data/style.css
+++ b/data/style.css
@@ -768,6 +768,10 @@ div#fil_div {
#fil_div .opts a.tsel { color: $maintext$; }
#filselect i { font-style: normal }
#fil_div table ul { margin: 0 0 0 15px }
+#fil_div .slider p { margin: 1px; }
+#fil_div .slider div { margin: 1px; border: 1px solid $secborder$; float: left; height: 12px; }
+#fil_div .slider div div { border-top: none; border-bottom: none; cursor: default; position: relative; height: 10px; margin: 1px; }
+#fil_div .slider span { margin-left: 5px }
diff --git a/lib/Multi/Feed.pm b/lib/Multi/Feed.pm
index 1a955e05..ea9cbcac 100644
--- a/lib/Multi/Feed.pm
+++ b/lib/Multi/Feed.pm
@@ -112,7 +112,7 @@ sub write_atom { # num, res, feed, time
$x->tag(updated => datetime($updated));
$x->tag(id => $VNDB::S{url}.$VNDB::S{atom_feeds}{$feed}[2]);
$x->tag(link => rel => 'self', type => 'application/atom+xml', href => "$VNDB::S{url}/feeds/$feed.atom", undef);
- $x->tag(link => rel => 'alternate', type => 'text/html', href => $VNDB::S{atom_feeds}{$feed}[2], undef);
+ $x->tag(link => rel => 'alternate', type => 'text/html', href => $VNDB::S{url}.$VNDB::S{atom_feeds}{$feed}[2], undef);
for(@$r) {
$x->tag('entry');
@@ -123,10 +123,10 @@ sub write_atom { # num, res, feed, time
if($_->{username}) {
$x->tag('author');
$x->tag(name => $_->{username});
- $x->tag(uri => '/u'.$_->{uid}) if $_->{uid};
+ $x->tag(uri => $VNDB::S{url}.'/u'.$_->{uid}) if $_->{uid};
$x->end;
}
- $x->tag(link => rel => 'alternate', type => 'text/html', href => $_->{id}, undef);
+ $x->tag(link => rel => 'alternate', type => 'text/html', href => $VNDB::S{url}.$_->{id}, undef);
$x->tag('summary', type => 'html', bb2html $_->{summary}) if $_->{summary};
$x->end('entry');
}
diff --git a/lib/Multi/Maintenance.pm b/lib/Multi/Maintenance.pm
index a754e618..e7c66a04 100644
--- a/lib/Multi/Maintenance.pm
+++ b/lib/Multi/Maintenance.pm
@@ -272,7 +272,7 @@ sub logrotate {
sub vnsearch_check {
$_[KERNEL]->call(pg => query =>
- 'SELECT id FROM vn WHERE NOT hidden AND c_search IS NULL LIMIT 1',
+ 'SELECT id FROM vn WHERE c_search IS NULL LIMIT 1',
undef, 'vnsearch_gettitles');
}
@@ -303,7 +303,7 @@ sub vnsearch_update { # num, res, vid, time
my @t = map +($_->{title}, $_->{original}), @$res;
# alias fields are a bit special
for (@$res) {
- push @t, split /,/, $_->{alias} if $_->{alias};
+ push @t, split /[\n,]/, $_->{alias} if $_->{alias};
}
my $t = normalize_titles(@t);
$_[KERNEL]->call(core => log => 'Updated search cache for v%d', $id);
diff --git a/lib/VNDB/DB/Chars.pm b/lib/VNDB/DB/Chars.pm
index be620378..86b3a859 100644
--- a/lib/VNDB/DB/Chars.pm
+++ b/lib/VNDB/DB/Chars.pm
@@ -8,7 +8,8 @@ use Exporter 'import';
our @EXPORT = qw|dbCharGet dbCharRevisionInsert dbCharImageId|;
-# options: id rev instance traitspoil trait_inc trait_exc char what results page
+# options: id rev instance tagspoil trait_inc trait_exc char what results page gender bloodt
+# bust_min bust_max waist_min waist_max hip_min hip_max height_min height_max weight_min weight_max role
# what: extended traits vns changes
sub dbCharGet {
my $self = shift;
@@ -16,7 +17,7 @@ sub dbCharGet {
page => 1,
results => 10,
what => '',
- traitspoil => 0,
+ tagspoil => 0,
@_
);
@@ -29,15 +30,30 @@ sub dbCharGet {
$o{notid} ? ( 'c.id <> ?' => $o{notid} ) : (),
$o{instance} ? ( 'cr.main = ?' => $o{instance} ) : (),
$o{vid} ? ( 'cr.id IN(SELECT cid FROM chars_vns WHERE vid = ?)' => $o{vid} ) : (),
+ defined $o{gender} ? ( 'cr.gender IN(!l)' => [ ref $o{gender} ? $o{gender} : [$o{gender}] ]) : (),
+ defined $o{bloodt} ? ( 'cr.bloodt IN(!l)' => [ ref $o{bloodt} ? $o{bloodt} : [$o{bloodt}] ]) : (),
+ defined $o{bust_min} ? ( 'cr.s_bust >= ?' => $o{bust_min} ) : (),
+ defined $o{bust_max} ? ( 'cr.s_bust <= ? AND cr.s_bust > 0' => $o{bust_max} ) : (),
+ defined $o{waist_min} ? ( 'cr.s_waist >= ?' => $o{waist_min} ) : (),
+ defined $o{waist_max} ? ( 'cr.s_waist <= ? AND cr.s_waist > 0' => $o{waist_max} ) : (),
+ defined $o{hip_min} ? ( 'cr.s_hip >= ?' => $o{hip_min} ) : (),
+ defined $o{hip_max} ? ( 'cr.s_hip <= ? AND cr.s_hip > 0' => $o{hip_max} ) : (),
+ defined $o{height_min} ? ( 'cr.height >= ?' => $o{height_min} ) : (),
+ defined $o{height_max} ? ( 'cr.height <= ? AND cr.height > 0' => $o{height_max} ) : (),
+ defined $o{weight_min} ? ( 'cr.weight >= ?' => $o{weight_min} ) : (),
+ defined $o{weight_max} ? ( 'cr.weight <= ? AND cr.weight > 0' => $o{weight_max} ) : (),
$o{search} ? (
'(cr.name ILIKE ? OR cr.original ILIKE ? OR cr.alias ILIKE ?)', [ map '%%'.$o{search}.'%%', 1..3 ] ) : (),
$o{char} ? (
'LOWER(SUBSTR(cr.name, 1, 1)) = ?' => $o{char} ) : (),
defined $o{char} && !$o{char} ? (
'(ASCII(cr.name) < 97 OR ASCII(cr.name) > 122) AND (ASCII(cr.name) < 65 OR ASCII(cr.name) > 90)' => 1 ) : (),
+ $o{role} ? (
+ 'EXISTS(SELECT 1 FROM chars_vns cvi WHERE cvi.cid = cr.id AND cvi.role IN(!l))',
+ [ ref $o{role} ? $o{role} : [$o{role}] ] ) : (),
$o{trait_inc} ? (
'c.id IN(SELECT cid FROM traits_chars WHERE tid IN(!l) AND spoil <= ? GROUP BY cid HAVING COUNT(tid) = ?)',
- [ ref $o{trait_inc} ? $o{trait_inc} : [$o{trait_inc}], $o{traitspoil}, ref $o{trait_inc} ? $#{$o{trait_inc}}+1 : 1 ]) : (),
+ [ ref $o{trait_inc} ? $o{trait_inc} : [$o{trait_inc}], $o{tagspoil}, ref $o{trait_inc} ? $#{$o{trait_inc}}+1 : 1 ]) : (),
$o{trait_exc} ? (
'c.id NOT IN(SELECT cid FROM traits_chars WHERE tid IN(!l))' => [ ref $o{trait_exc} ? $o{trait_exc} : [$o{trait_exc}] ] ) : (),
);
diff --git a/lib/VNDB/DB/VN.pm b/lib/VNDB/DB/VN.pm
index 474066ce..473fa92c 100644
--- a/lib/VNDB/DB/VN.pm
+++ b/lib/VNDB/DB/VN.pm
@@ -11,7 +11,7 @@ our @EXPORT = qw|dbVNGet dbVNRevisionInsert dbVNImageId dbScreenshotAdd dbScreen
# Options: id, rev, char, search, length, lang, olang, plat, tag_inc, tag_exc, tagspoil,
-# hasani, hasshot, ul_notblack, ul_onwish, results, page, what, sort, reverse
+# hasani, hasshot, ul_notblack, ul_onwish, results, page, what, sort, reverse, inc_hidden
# What: extended anime relations screenshots relgraph rating ranking changes
# Sort: id rel pop rating title tagscore rand
sub dbVNGet {
@@ -66,7 +66,7 @@ sub dbVNGet {
$uid && defined $o{ul_onlist} ? (
'v.id !s IN(SELECT vid FROM vnlists WHERE uid = ?)' => [ $o{ul_onlist} ? '' : 'NOT', $uid ] ) : (),
# don't fetch hidden items unless we ask for an ID
- !$o{id} && !$o{rev} ? (
+ !$o{id} && !$o{rev} && !$o{inc_hidden} ? (
'v.hidden = FALSE' => 0 ) : (),
# optimize fetching random entries (only when there are no other filters present, otherwise this won't work well)
$o{sort} eq 'rand' && $o{results} <= 10 && !grep(!/^(?:results|page|what|sort|tagspoil)$/, keys %o) ? (
@@ -107,7 +107,7 @@ sub dbVNGet {
my $order = sprintf {
id => 'id %s',
- rel => 'c_released %s',
+ rel => 'c_released %s, title ASC',
pop => 'c_popularity %s NULLS LAST',
rating => 'c_rating %s NULLS LAST',
title => 'title %s',
diff --git a/lib/VNDB/Handler/Chars.pm b/lib/VNDB/Handler/Chars.pm
index 9c8a1b5e..c707a453 100644
--- a/lib/VNDB/Handler/Chars.pm
+++ b/lib/VNDB/Handler/Chars.pm
@@ -451,33 +451,39 @@ sub list {
my($self, $fch) = @_;
my $f = $self->formValidate(
- { get => 'p', required => 0, default => 1, template => 'int' },
- { get => 'q', required => 0, default => '' },
+ { get => 'p', required => 0, default => 1, template => 'int' },
+ { get => 'q', required => 0, default => '' },
+ { get => 'fil', required => 0, default => '' },
);
return $self->resNotFound if $f->{_err};
- my($list, $np) = $self->dbCharGet(
+ my($list, $np) = $self->filFetchDB(char => $f->{fil}, {}, {
$fch ne 'all' ? ( char => $fch ) : (),
$f->{q} ? ( search => $f->{q} ) : (),
results => 50,
page => $f->{p},
what => 'vns',
- );
+ });
$self->htmlHeader(title => mt '_charb_title');
my $quri = uri_escape($f->{q});
+ form action => '/c/all', 'accept-charset' => 'UTF-8', method => 'get';
div class => 'mainbox';
h1 mt '_charb_title';
- form action => '/c/all', 'accept-charset' => 'UTF-8', method => 'get';
- $self->htmlSearchBox('c', $f->{q});
- end;
+ $self->htmlSearchBox('c', $f->{q});
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
a href => "/c/$_?q=$quri", $_ eq $fch ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
}
end;
+
+ a id => 'filselect', href => '#c';
+ lit '<i>&#9656;</i> '.mt('_js_fil_filters').'<i></i>';
+ end;
+ input type => 'hidden', class => 'hidden', name => 'fil', id => 'fil', value => $f->{fil};
end;
+ end 'form';
if(!@$list) {
div class => 'mainbox';
diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm
index 52db6edf..1369c1e2 100644
--- a/lib/VNDB/Handler/Producers.pm
+++ b/lib/VNDB/Handler/Producers.pm
@@ -304,7 +304,7 @@ sub edit {
end;
end;
td class => 'tc_add';
- a href => '#', mt '_pedit_rel_addbut';
+ a href => '#', mt '_js_add';
end;
end;
end 'table';
diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm
index f0fdac3f..0291ba0a 100644
--- a/lib/VNDB/Handler/Releases.pm
+++ b/lib/VNDB/Handler/Releases.pm
@@ -456,7 +456,7 @@ sub _form {
option value => 2, selected => 'selected', mt '_redit_form_prod_pub';
option value => 3, mt '_redit_form_prod_both';
end; end;
- td class => 'tc_add'; a id => 'producer_add', href => '#', mt '_redit_form_prod_addbut'; end;
+ td class => 'tc_add'; a id => 'producer_add', href => '#', mt '_js_add'; end;
end; end 'table';
}],
],
@@ -469,7 +469,7 @@ sub _form {
h2 mt('_redit_form_vn_add');
div;
input id => 'vn_input', type => 'text', class => 'text';
- a href => '#', id => 'vn_add', mt '_redit_form_vn_addbut';
+ a href => '#', id => 'vn_add', mt '_js_add';
end;
}],
],
diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm
index 3d698fc3..39388a30 100644
--- a/lib/VNDB/Handler/Tags.pm
+++ b/lib/VNDB/Handler/Tags.pm
@@ -390,7 +390,7 @@ sub taglinks {
if($f->{u}) {
my $o = $self->dbUserGet(uid => $f->{u})->[0];
li;
- txt '['; a href => $url->(u=>0), mt '_taglink_fil_remove'; txt '] ';
+ txt '['; a href => $url->(u=>0), mt '_js_remove'; txt '] ';
txt mt '_taglink_fil_user'; txt ' ';
a href => "/u$o->{id}", $o->{username};
end;
@@ -398,7 +398,7 @@ sub taglinks {
if($f->{t}) {
my $o = $self->dbTagGet(id => $f->{t})->[0];
li;
- txt '['; a href => $url->(t=>0), mt '_taglink_fil_remove'; txt '] ';
+ txt '['; a href => $url->(t=>0), mt '_js_remove'; txt '] ';
txt mt '_taglink_fil_tag'; txt ' ';
a href => "/g$o->{id}", $o->{name};
end;
@@ -406,7 +406,7 @@ sub taglinks {
if($f->{v}) {
my $o = $self->dbVNGet(id => $f->{v})->[0];
li;
- txt '['; a href => $url->(v=>0), mt '_taglink_fil_remove'; txt '] ';
+ txt '['; a href => $url->(v=>0), mt '_js_remove'; txt '] ';
txt mt '_taglink_fil_vn'; txt ' ';
a href => "/v$o->{id}", $o->{title};
end;
diff --git a/lib/VNDB/Handler/Traits.pm b/lib/VNDB/Handler/Traits.pm
index f3abdfeb..0a21011c 100644
--- a/lib/VNDB/Handler/Traits.pm
+++ b/lib/VNDB/Handler/Traits.pm
@@ -27,6 +27,7 @@ sub traitpage {
my $f = $self->formValidate(
{ get => 'p', required => 0, default => 1, template => 'int' },
{ get => 'm', required => 0, default => undef, enum => [qw|0 1 2|] },
+ { get => 'fil', required => 0, default => '' },
);
return $self->resNotFound if $f->{_err};
my $tagspoil = $self->reqCookie('tagspoil')||'';
@@ -83,14 +84,15 @@ sub traitpage {
childtags($self, mt('_traitp_childs'), 'i', $t) if @{$t->{childs}};
if(!$t->{meta} && $t->{state} == 2) {
- my($chars, $np) = $self->dbCharGet(
+ my($chars, $np) = $self->filFetchDB(char => $f->{fil}, {}, {
trait_inc => $trait,
- traitspoil => $f->{m},
+ tagspoil => $f->{m},
results => 50,
page => $f->{p},
what => 'vns',
- );
+ });
+ form action => "/i$t->{id}", 'accept-charset' => 'UTF-8', method => 'get';
div class => 'mainbox';
h1 mt '_traitp_charlist';
@@ -101,12 +103,17 @@ sub traitpage {
a href => "/i$trait?m=2", $f->{m} == 2 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 2);return true;", mt '_tagp_spoil2';
end;
+ a id => 'filselect', href => '#c';
+ lit '<i>&#9656;</i> '.mt('_js_fil_filters').'<i></i>';
+ end;
+ input type => 'hidden', class => 'hidden', name => 'fil', id => 'fil', value => $f->{fil};
+
if(!@$chars) {
p; br; br; txt mt '_traitp_nochars'; end;
}
p; br; txt mt '_traitp_cached'; end;
end 'div';
-
+ end 'form';
@$chars && $self->charBrowseTable($chars, $np, $f, "/i$trait?m=$f->{m}");
}
diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index 0309a01c..56031472 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -10,13 +10,71 @@ use VNDB::Func;
TUWF::register(
qr{v(?:([1-9]\d*)(?:\.([1-9]\d*))?/edit|/new)}
=> \&edit,
+ qr{v/add} => \&addform,
qr{xml/vn\.xml} => \&vnxml,
qr{xml/screenshots\.xml} => \&scrxml,
);
+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 => 'title', maxlength => 250 },
+ { post => 'original', required => 0, maxlength => 250, default => '' },
+ { post => 'alias', required => 0, maxlength => 500, default => '' },
+ { post => 'continue_ign',required => 0 },
+ );
+
+ # look for duplicates
+ if(!$frm->{_err} && !$frm->{continue_ign}) {
+ $l = $self->dbVNGet(search => $frm->{title}, what => 'changes', results => 50, inc_hidden => 1);
+ push @$l, @{$self->dbVNGet(search => $frm->{original}, what => 'changes', results => 50, inc_hidden => 1)} if $frm->{original};
+ $_ && push @$l, $self->dbVNGet(search => $_, what => 'changes', results => 50, inc_hidden => 1) for(split /\n/, $frm->{alias});
+ my %ids = map +($_->{id}, $_), @$l;
+ $l = [ map $ids{$_}, sort { $ids{$a}{title} cmp $ids{$b}{title} } keys %ids ];
+ }
+
+ return edit($self, undef, undef, 1) if !@$l && !$frm->{_err};
+ }
+
+ $self->htmlHeader(title => mt('_vnedit_title_add'), noindex => 1);
+ if(@$l) {
+ div class => 'mainbox';
+ h1 mt '_vnedit_dup_title';
+ div class => 'warning';
+ p; lit mt '_vnedit_dup_msg'; end;
+ end;
+ ul;
+ for(@$l) {
+ li;
+ a href => "/v$_->{id}", title => $_->{original}||$_->{title}, "v$_->{id}: ".shorten($_->{title}, 50);
+ b class => 'standout', ' deleted' if $_->{hidden};
+ end;
+ }
+ end;
+ end 'div';
+ }
+
+ $self->htmlForm({ frm => $frm, action => '/v/add', continue => @$l ? 2 : 1 },
+ vn_add => [ mt('_vnedit_title_add'),
+ [ input => short => 'title', name => mt '_vnedit_frm_title' ],
+ [ input => short => 'original', name => mt '_vnedit_original' ],
+ [ static => content => mt '_vnedit_original_msg' ],
+ [ textarea => short => 'alias', name => mt('_vnedit_alias'), rows => 4 ],
+ [ static => content => mt '_vnedit_alias_msg' ],
+ ]);
+ $self->htmlFooter;
+}
+
+
sub edit {
- my($self, $vid, $rev) = @_;
+ my($self, $vid, $rev, $nosubmit) = @_;
my $v = $vid && $self->dbVNGet(id => $vid, what => 'extended screenshots relations anime changes', $rev ? (rev => $rev) : ())->[0];
return $self->resNotFound if $vid && !$v->{id};
@@ -36,7 +94,7 @@ sub edit {
my $frm;
if($self->reqMethod eq 'POST') {
- return if !$self->authCheckCode;
+ return if !$nosubmit && !$self->authCheckCode;
$frm = $self->formValidate(
{ post => 'title', maxlength => 250 },
{ post => 'original', required => 0, maxlength => 250, default => '' },
@@ -53,16 +111,16 @@ sub edit {
{ post => 'vnrelations', required => 0, default => '', maxlength => 5000 },
{ post => 'screenshots', required => 0, default => '', maxlength => 1000 },
{ post => 'editsum', required => 0, maxlength => 5000 },
- { post => 'ihid', required => 0 },
- { post => 'ilock', required => 0 },
+ { post => 'ihid', required => 0 },
+ { post => 'ilock', required => 0 },
);
- push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc});
+ push @{$frm->{_err}}, 'badeditsum' if !$nosubmit && (!$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc}));
# handle image upload
- $frm->{image} = _uploadimage($self, $frm);
+ $frm->{image} = _uploadimage($self, $frm) if !$nosubmit;
- if(!$frm->{_err}) {
+ if(!$nosubmit && !$frm->{_err}) {
# parse and re-sort fields that have multiple representations of the same information
my $anime = { map +($_=>1), grep /^[0-9]+$/, split /[ ,]+/, $frm->{anime} };
my $relations = [ map { /^([a-z]+),([0-9]+),([01]),(.+)$/ && (!$vid || $2 != $vid) ? [ $1, $2, $3, $4 ] : () } split /\|\|\|/, $frm->{vnrelations} ];
@@ -169,8 +227,8 @@ sub _form {
vn_img => [ mt('_vnedit_image'), [ static => nolabel => 1, content => sub {
div class => 'img';
p mt '_vnedit_image_none' if !$frm->{image};
- p mt '_vnedit_image_processing' if $frm->{image} < 0;
- img src => imgurl(cv => $frm->{image}) if $frm->{image} > 0;
+ p mt '_vnedit_image_processing' if $frm->{image} && $frm->{image} < 0;
+ img src => imgurl(cv => $frm->{image}) if $frm->{image} && $frm->{image} > 0;
end;
div;
@@ -220,7 +278,7 @@ sub _form {
end;
td class => 'tc_title', $v ? $v->{title} : '';
td class => 'tc_add';
- a href => '#', mt '_vnedit_rel_addbut';
+ a href => '#', mt '_js_add';
end;
end;
end 'table';
diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm
index 60e7b237..73e2c5ba 100644
--- a/lib/VNDB/Util/CommonHTML.pm
+++ b/lib/VNDB/Util/CommonHTML.pm
@@ -84,7 +84,7 @@ sub htmlMainTabs {
if($type eq 'u' && $self->authCan('usermod')) {
li $sel eq 'del' ? (class => 'tabselected') : ();
- a href => "/$id/del", mt '_mtabs_del';
+ a href => "/$id/del", mt '_js_remove';
end;
}
diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm
index 21eeb980..13ec56f9 100644
--- a/lib/VNDB/Util/FormHTML.pm
+++ b/lib/VNDB/Util/FormHTML.pm
@@ -165,10 +165,12 @@ sub htmlFormPart {
# Generates a form, first argument is a hashref with global options, keys:
-# frm => the $frm as returned by formValidate,
-# action => The location the form should POST to (also used as form id)
-# upload => 1/0, adds an enctype.
-# editsum => 1/0, adds an edit summary field before the submit button
+# frm => the $frm as returned by formValidate,
+# action => The location the form should POST to (also used as form id)
+# upload => 1/0, adds an enctype.
+# nosubmit => 1/0, hides the submit button
+# editsum => 1/0, adds an edit summary field before the submit button
+# continue => 2/1/0, replace submit button with continue buttons
# The other arguments are a list of subforms in the form
# of (subform-name => [form parts]). Each subform is shown as a
# (JavaScript-powered) tab, and has it's own 'mainbox'. This function
@@ -235,7 +237,12 @@ sub htmlForm {
textarea name => 'editsum', id => 'editsum', rows => 4, cols => 50, $options->{frm}{editsum}||'';
br;
}
- input type => 'submit', value => mt('_form_submit'), class => 'submit';
+ if(!$options->{continue}) {
+ input type => 'submit', value => mt('_form_submit'), class => 'submit';
+ } else {
+ input type => 'submit', value => mt('_form_continue'), class => 'submit';
+ input type => 'submit', name => 'continue_ign', value => mt('_form_continue_ign'), class => 'submit', style => 'width: auto' if $options->{continue} == 2;
+ }
end;
end 'div';
}
diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm
index 752f6728..7507d682 100644
--- a/lib/VNDB/Util/LayoutHTML.pm
+++ b/lib/VNDB/Util/LayoutHTML.pm
@@ -100,7 +100,7 @@ sub _menu {
a href => '/g/links?u='.$self->authInfo->{id}, mt '_menu_mytags'; br;
br;
if($self->authCan('edit')) {
- a href => '/v/new', mt '_menu_addvn'; br;
+ a href => '/v/add', mt '_menu_addvn'; br;
a href => '/p/new', mt '_menu_addproducer'; br;
}
if($self->authCan('charedit')) {
diff --git a/lib/VNDB/Util/Misc.pm b/lib/VNDB/Util/Misc.pm
index 5406fe06..04114483 100644
--- a/lib/VNDB/Util/Misc.pm
+++ b/lib/VNDB/Util/Misc.pm
@@ -13,11 +13,12 @@ our @EXPORT = qw|filFetchDB ieCheck|;
my %filfields = (
vn => [qw|length hasani tag_inc tag_exc taginc tagexc tagspoil lang olang plat ul_notblack ul_onwish ul_voted ul_onlist|],
release => [qw|type patch freeware doujin date_before date_after released minage lang olang resolution plat med voiced ani_story ani_ero|],
+ char => [qw|gender bloodt bust_min bust_max waist_min waist_max hip_min hip_max height_min height_max weight_min weight_max trait_inc trait_exc tagspoil role|],
);
# Arguments:
-# type ('vn' or 'release'),
+# type ('vn', 'release' or 'char'),
# filter overwrite (string or undef),
# when defined, these filters will be used instead of the preferences,
# must point to a variable, will be modified in-place with the actually used filters
@@ -30,7 +31,7 @@ sub filFetchDB {
my($self, $type, $overwrite, $pre, $post) = @_;
$pre = {} if !$pre;
$post = {} if !$post;
- my $dbfunc = $self->can($type eq 'vn' ? 'dbVNGet' : 'dbReleaseGet');
+ my $dbfunc = $self->can($type eq 'vn' ? 'dbVNGet' : $type eq 'release' ? 'dbReleaseGet' : 'dbCharGet');
my $prefname = 'filter_'.$type;
my $pref = $self->authPref($prefname);
diff --git a/util/jsgen.pl b/util/jsgen.pl
index f046fe1a..26815423 100755
--- a/util/jsgen.pl
+++ b/util/jsgen.pl
@@ -111,6 +111,9 @@ sub jsgen {
$common .= sprintf "animated = [ %s ];\n", join ', ', @{$S{animated}};
$common .= sprintf "voiced = [ %s ];\n", join ', ', @{$S{voiced}};
$common .= sprintf "vn_lengths = [ %s ];\n", join ', ', @{$S{vn_lengths}};
+ $common .= sprintf "blood_types = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{blood_types}};
+ $common .= sprintf "genders = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{genders}};
+ $common .= sprintf "char_roles = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{char_roles}};
$common .= sprintf "L10N_LANG = [ %s ];\n", join(', ', map
sprintf('["%s","%s"]', $_, $lang{$_}{"_lang_$_"}||$lang{en}{"_lang_$_"}),
VNDB::L10N::languages());
diff --git a/util/sql/all.sql b/util/sql/all.sql
index eac8d58a..bb5829f7 100644
--- a/util/sql/all.sql
+++ b/util/sql/all.sql
@@ -104,8 +104,7 @@ CREATE TRIGGER notify_dbedit AFTER UPDATE ON chars
CREATE TRIGGER notify_announce AFTER INSERT ON threads_posts FOR EACH ROW WHEN (NEW.num = 1) EXECUTE PROCEDURE notify_announce();
CREATE TRIGGER vn_vnsearch_notify AFTER UPDATE ON vn FOR EACH ROW
- WHEN (OLD.c_search IS NOT NULL AND NEW.c_search IS NULL AND NOT NEW.hidden
- OR NEW.hidden IS DISTINCT FROM OLD.hidden
+ WHEN (OLD.c_search IS NOT NULL AND NEW.c_search IS NULL
OR NEW.latest IS DISTINCT FROM OLD.latest
) EXECUTE PROCEDURE vn_vnsearch_notify();
CREATE TRIGGER vn_vnsearch_notify AFTER UPDATE ON releases FOR EACH ROW
diff --git a/util/sql/func.sql b/util/sql/func.sql
index 3af04562..e5be2fde 100644
--- a/util/sql/func.sql
+++ b/util/sql/func.sql
@@ -738,20 +738,16 @@ $$ LANGUAGE plpgsql;
-- Check for updates to vn.c_search
-- 1. NOTIFY is sent when vn.c_search goes from non-NULL to NULL
-- vn.c_search is set to NULL when:
--- 2. UPDATE on VN with the hidden field going from TRUE to FALSE
--- 3. VN add/edit of which the title/original/alias fields differ from previous revision
--- 4. Release gets hidden or unhidden
--- 5. Release add/edit of which the title/original/vn fields differ from the previous revision
+-- 2. VN add/edit of which the title/original/alias fields differ from previous revision
+-- 3. Release gets hidden or unhidden
+-- 4. Release add/edit of which the title/original/vn fields differ from the previous revision
CREATE OR REPLACE FUNCTION vn_vnsearch_notify() RETURNS trigger AS $$
BEGIN
IF TG_TABLE_NAME = 'vn' THEN
-- 1.
- IF NEW.c_search IS NULL AND NOT NEW.hidden THEN
+ IF NEW.c_search IS NULL THEN
NOTIFY vnsearch;
-- 2.
- ELSIF NEW.hidden IS DISTINCT FROM OLD.hidden THEN
- UPDATE vn SET c_search = NULL WHERE id = NEW.id;
- -- 3.
ELSIF NEW.latest IS DISTINCT FROM OLD.latest THEN
IF EXISTS(SELECT 1 FROM vn_rev v1, vn_rev v2
WHERE v1.id = OLD.latest AND v2.id = NEW.latest
@@ -761,7 +757,7 @@ BEGIN
END IF;
END IF;
ELSIF TG_TABLE_NAME = 'releases' THEN
- -- 4. & 5.
+ -- 3. & 4.
IF NEW.hidden IS DISTINCT FROM OLD.hidden OR (
NEW.latest IS DISTINCT FROM OLD.latest AND (
EXISTS(
diff --git a/util/updates/update_2.22.sql b/util/updates/update_2.22.sql
new file mode 100644
index 00000000..3268481e
--- /dev/null
+++ b/util/updates/update_2.22.sql
@@ -0,0 +1,11 @@
+
+
+DROP TRIGGER vn_vnsearch_notify ON vn;
+
+CREATE TRIGGER vn_vnsearch_notify AFTER UPDATE ON vn FOR EACH ROW
+ WHEN (OLD.c_search IS NOT NULL AND NEW.c_search IS NULL
+ OR NEW.latest IS DISTINCT FROM OLD.latest
+ ) EXECUTE PROCEDURE vn_vnsearch_notify();
+
+\i util/sql/func.sql
+