/* function/attribute prefixes: * date -> Date selector * dd -> dropdown * ds -> dropdown search * fil -> Filter selector * iv -> image viewer * jt -> Javascript Tabs * med -> Release media selector * prr -> Producer relation editor * rl -> Release List dropdown * rpr -> Release <-> producer linking * rvn -> Release <-> visual novel linking * scr -> VN screenshot uploader * tgl -> VN tag linking * tvs -> VN page tag spoilers * vnr -> VN relation editor */ /* Internationalization note: * The translation keys to be inserted in the header of this file are parsed * from the source code. So when using mt(), make sure it is in the following * format: * mt('', * or * mt('') * The single quotes and (lack of) spaces are significant! * * To use non-exact translation keys as argument to mt(), make sure to * indicate which keys should be inserted in the header by adding a comment * containing the following format: * l10n // * any keys matching that regex will be included. * * In the case of an mt('') without any extra arguments, the entire * function call may be replaced by the TL string. In such a case mt() * behaves similar to a preprocessor macro in C. */ var expanded_icon = '▾'; var collapsed_icon = '▸'; /* M I N I M A L J A V A S C R I P T L I B R A R Y */ var http_request = false; function ajax(url, func, async) { if(!async && http_request) http_request.abort(); var req = (window.ActiveXObject) ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(); if(req == null) return alert("Your browser does not support the functionality this website requires."); if(!async) http_request = req; req.onreadystatechange = function() { if(!req || req.readyState != 4 || !req.responseText) return; if(req.status != 200) return alert('Whoops, error! :('); func(req); }; url += (url.indexOf('?')>=0 ? ';' : '?')+(Math.floor(Math.random()*999)+1); req.open('GET', url, true); req.send(null); } function setCookie(n,v) { var date = new Date(); date.setTime(date.getTime()+(365*24*60*60*1000)); document.cookie = cookie_prefix+n+'='+v+'; expires='+date.toGMTString()+'; path=/'; } function getCookie(n) { var l = document.cookie.split(';'); n = cookie_prefix+n; for(var i=0; i createTextNode * tag('tagname', tag(), 'string', ..) -> createElement(), appendChild(), .. * tag('tagname', { class: 'meh', title: 'Title' }) -> createElement(), setAttribute().. * tag('tagname', { }, ) -> create, setattr, append */ function tag() { if(arguments.length == 1) return typeof arguments[0] != 'object' ? document.createTextNode(arguments[0]) : arguments[0]; var el = typeof document.createElementNS != 'undefined' ? document.createElementNS('http://www.w3.org/1999/xhtml', arguments[0]) : document.createElement(arguments[0]); for(var i=1; i l ? v.substr(0, l-3)+'...' : v; } /* maketext function, less powerful than the Perl equivalent: * - Only supports [_n], ~[, ~] * - When it finds [quant,_n,..], it will only return the first argument (and doesn't support ~ in an argument) * assumes that a TL structure called 'L10N_STR' is defined in the header of this file */ function mt() { var key = arguments[0]; var val = L10N_STR[key] ? L10N_STR[key] : key; for(var i=1; i= 0) val = val.replace(expr, arguments[i]); } val = val.replace(/\[quant,_\d+\,([^,]+)[^\]]+\]/g, "$1"); while(val.indexOf('~[') >= 0 || val.indexOf('~]') >= 0) val = val.replace('~[', '[').replace('~]', ']'); return val; } /* I M A G E V I E W E R */ function ivInit() { var init = 0; var l = byName('a'); for(var i=0;i 4 && !hasClass(ol[i], 'hidden') && ol[i].id != 'ivprev' && ol[i].id != 'ivnext') l[l.length] = ol[i]; for(i=0;i ww || h+70 > wh) { full.href = u; setText(full, w+'x'+h); full.style.visibility = 'visible'; if(w/h > ww/wh) { // width++ h *= (ww-100)/w; w = ww-100; } else { // height++ w *= (wh-70)/h; h = wh-70; } } else full.style.visibility = 'hidden'; var dw = w; var dh = h+20; dw = dw < 200 ? 200 : dw; // update document setClass(view, 'hidden', false); setContent(byId('ivimg'), tag('img', {src:u, onclick:ivClose, onload: function() { setClass(byId('ivimgload'), 'hidden', true); }, style: 'width: '+w+'px; height: '+h+'px' })); view.style.width = dw+'px'; view.style.height = dh+'px'; view.style.left = ((ww - dw) / 2 - 10)+'px'; view.style.top = ((wh - dh) / 2 + st - 20)+'px'; byId('ivimgload').style.left = ((ww - 100) / 2 - 10)+'px'; byId('ivimgload').style.top = ((wh - 20) / 2 + st)+'px'; setClass(byId('ivimgload'), 'hidden', false); return false; } function ivClose() { setClass(byId('iv_view'), 'hidden', true); setClass(byId('ivimgload'), 'hidden', true); setText(byId('ivimg'), ''); return false; } ivInit(); /* D R O P D O W N */ function ddInit(obj, align, contents) { obj.dd_align = align; // see ddRefresh for details obj.dd_contents = contents; document.onmousemove = ddMouseMove; document.onscroll = ddHide; if(!byId('dd_box')) addBody(tag('div', {id:'dd_box', 'class':'hidden', dd_used: false})); } function ddHide() { var box = byId('dd_box'); setText(box, ''); setClass(box, 'hidden', true); box.dd_used = false; box.dd_lnk = null; } function ddMouseMove(e) { e = e || window.event; var lnk = e.target || e.srcElement; while(lnk && (lnk.nodeType == 3 || !lnk.dd_align)) lnk = lnk.parentNode; var box = byId('dd_box'); if(!box.dd_used && !lnk) return; if(box.dd_used) { var mouseX = e.pageX || (e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft); var mouseY = e.pageY || (e.clientY + document.body.scrollTop + document.documentElement.scrollTop); if((mouseX < ddx-10 || mouseX > ddx+box.offsetWidth+10 || mouseY < ddy-10 || mouseY > ddy+box.offsetHeight+10) || (lnk && lnk == box.dd_lnk)) ddHide(); } if(!box.dd_used && lnk || box.dd_used && lnk && box.dd_lnk != lnk) { box.dd_lnk = lnk; box.dd_used = true; if(!ddRefresh()) ddHide(); } } function ddRefresh() { var box = byId('dd_box'); if(!box.dd_used) return false; var lnk = box.dd_lnk; var content = lnk.dd_contents(lnk, box); if(content == null) return false; setContent(box, content); setClass(box, 'hidden', false); var o = lnk; ddx = ddy = 0; do { ddx += o.offsetLeft; ddy += o.offsetTop; } while(o = o.offsetParent); if(lnk.dd_align == 'left') ddx -= box.offsetWidth; if(lnk.dd_align == 'tagmod') ddx += lnk.offsetWidth-35; if(lnk.dd_align == 'bottom') ddy += lnk.offsetHeight; box.style.left = ddx+'px'; box.style.top = ddy+'px'; return true; } // release list dropdown on VN pages function rlDropDown(lnk) { var relid = lnk.id.substr(6); var st = getText(lnk); if(st == mt('_js_loading')) return null; var o = tag('ul', null); for(var i=0; i=1980; i--) year.appendChild(tag('option', {value: i}, i)); var month = tag('select', {style: 'width: 70px', onfocus:serfunc, onchange: dateSerialize}, tag('option', {value:99}, mt('_js_date_month'))); for(var i=1; i<=12; i++) month.appendChild(tag('option', {value: i}, i)); var day = tag('select', {style: 'width: 70px', onfocus:serfunc, onchange: dateSerialize}, tag('option', {value:99}, mt('_js_date_day'))); for(var i=1; i<=31; i++) day.appendChild(tag('option', {value: i}, i)); var div = tag('div', {date_obj: obj, date_serfunc: serfunc, date_val: obj ? obj.value : 0}, year, month, day); dateSet(div, obj ? obj.value : 0); return obj ? obj.parentNode.insertBefore(div, obj) : div; } function dateSet(div, val) { val = typeof val == 'object' ? val[0] : val; val = Math.floor(val) || 0; val = [ Math.floor(val/10000), Math.floor(val/100)%100, val%100 ]; if(val[1] == 0) val[1] = 99; if(val[2] == 0) val[2] = 99; var l = byName(div, 'select'); for(var i=0; i0 ? l[i-1] : l[l.length-1]; else sel = l[i+1] ? l[i+1] : l[0]; } obj.ds_selectedId = sel.id.substr(7); } // set selected class for(var i=0; i1; i++) { var rel = rels[i].split(',', 4); vnrAdd(rel[0], rel[1], rel[2]==1?true:false, rel[3]); } vnrEmpty(); // make sure the title is up-to-date byId('title').onchange = function() { var l = byClass(byId('jt_box_vn_rel'), 'td', 'tc_title'); for(i=0; i 1; i++) medAdd(med[i].split(' ')[0], Math.floor(med[i].split(' ')[1])); medAdd('', 0); } function medAdd(med, qty) { var qsel = tag('select', {'class':'qty', onchange:medSerialize}, tag('option', {value:0}, mt('_redit_form_med_quantity'))); for(var i=1; i<=20; i++) qsel.appendChild(tag('option', {value:i, selected: qty==i}, i)); var msel = tag('select', {'class':'medium', onchange: med == '' ? medFormAdd : medSerialize}); if(med == '') msel.appendChild(tag('option', {value:''}, mt('_redit_form_med_medium'))); for(var i=0; i1; i++) { var r = scr[i].split(','); scrAdd(r[0], r[1], r[2]); } scrLast(); scrCheckStatus(); scrSetSubmit(); } function scrSetSubmit() { var frm = byId('screenshots'); while(frm.nodeName.toLowerCase() != 'form') frm = frm.parentNode; oldfunc = frm.onsubmit; frm.onsubmit = function() { var loading = 0; var norelease = 0; var l = byName(byId('scr_table'), 'tr'); for(var i=0; i 0) loading = 1; else if(rel.options[rel.selectedIndex].value == 0) norelease = 1; } if(loading) { alert(mt('_vnedit_scr_frmloading')); return false; } else if(norelease) { alert(mt('_vnedit_scr_frmnorel')); return false; } else if(oldfunc) return oldfunc(); }; } function scrURL(id, t) { return scrStaticURL+'/s'+t+'/'+(id%100<10?'0':'')+(id%100)+'/'+id+'.jpg'; } function scrAdd(id, nsfw, rel) { // tr.scr_status = 0: done, 1: uploading, 2: waiting for thumbnail var tr = tag('tr', { id:'scr_tr_'+id, scr_id: id, scr_status: id?2:1, scr_rel: rel, scr_nsfw: nsfw}, tag('td', { 'class': 'thumb'}, mt('_js_loading')), tag('td', tag('b', id ? mt('_vnedit_scr_fetching') : mt('_vnedit_scr_uploading')), tag('br', null), id ? null : mt('_vnedit_scr_upl_msg'), tag('br', null), id ? null : tag('a', {href:'#', onclick:scrDel}, mt('_vnedit_scr_cancel')) ) ); byId('scr_table').appendChild(tr); scrStripe(); return tr; } function scrLast() { if(byId('scr_last')) byId('scr_table').removeChild(byId('scr_last')); var full = byName(byId('scr_table'), 'tr').length >= 10; var rel = tag('select', {onchange: function(){scrDefRel=this.options[this.selectedIndex].value}, 'class':'scr_relsel', 'id':'scradd_relsel'}); for(var j=0; j0, 'class':'scr_nsfw'}), tag('label', {'for':nsfwid}, mt('_vnedit_scr_nsfw')), tag('br', null), rel ); } scrSerialize(); ivInit(); clearTimeout(ti); setTimeout(scrCheckStatus, 1000); }); } function scrDel(what) { var tr = what && what.scr_status != null ? what : this; while(tr.nodeName.toLowerCase() != 'tr') tr = tr.parentNode; tr.scr_status = null; if(tr.scr_upl && byId(tr.scr_upl)) byId(tr.scr_upl).parentNode.removeChild(byId(tr.scr_upl)); byId('scr_table').removeChild(tr); scrSerialize(); scrLast(); return false; } function scrUpload() { scrUplNr++; // create temporary form var ifid = 'scr_upl_'+scrUplNr; var frm = tag('form', {method: 'post', action:'/xml/screenshots.xml?upload='+scrUplNr, target: ifid, enctype:'multipart/form-data'}); var ifr = tag('iframe', {id:ifid, name:ifid, src:'about:blank', onload:scrUploadComplete}); addBody(tag('div', {'class':'scr_uploader'}, ifr, frm)); // submit form var upl = byId('scr_upload'); upl.id = upl.name = 'scr_upl_file_'+scrUplNr; frm.appendChild(upl); frm.submit(); ifr.scr_tr = scrAdd(0, 0, 0); ifr.scr_upl = ifid; ifr.scr_tr.scr_rel = byId('scradd_relsel').options[byId('scradd_relsel').selectedIndex].value; scrLast(); return false; } function scrUploadComplete() { var ifr = this; var fr = window.frames[ifr.id]; if(fr.location.href.indexOf('screenshots') < 0) return; var tr = ifr.scr_tr; if(tr && tr.scr_status == 1) { try { tr.scr_id = fr.window.document.getElementsByTagName('image')[0].getAttribute('id'); } catch(e) { tr.scr_id = -10; } if(tr.scr_id < 0) { alert(tr.scr_id == -10 ? mt('_vnedit_scr_oops') : tr.scr_id == -1 ? mt('_vnedit_scr_errformat') : mt('_vnedit_scr_errempty')); scrDel(tr); } else { tr.id = 'scr_tr_'+tr.scr_id; tr.scr_status = 2; setContent(byName(tr, 'td')[1], tag('b', mt('_vnedit_scr_genthumb')), tag('br', null), mt('_vnedit_scr_genthumb_msg') ); } } tr.scr_upl = null; /* remove the
in a timeout, otherwise some browsers think the page is still loading */ setTimeout(function() { ifr.parentNode.parentNode.removeChild(ifr.parentNode) }, 1000); } function scrSerialize() { var r = []; var l = byName(byId('scr_table'), 'tr'); for(var i=0; i= tglSpoilers.length) this.tgl_spoil = 0; setText(this, tglSpoilers[this.tgl_spoil]); tglSerialize(); ddRefresh(); } function tglSpoilDD(lnk) { var lst = tag('ul', null); for(var i=0; i0&&vote>=num); } } function tglAdd() { var tg = byId('tagmod_tag'); var add = byId('tagmod_add'); tag.disabled = add.disabled = true; add.value = mt('_js_loading'); ajax('/xml/tags.xml?q=name:'+encodeURIComponent(tg.value), function(hr) { tg.disabled = add.disabled = false; tg.value = ''; add.value = mt('_tagv_add'); var items = hr.responseXML.getElementsByTagName('item'); if(items.length < 1) return alert(mt('_tagv_notfound')); if(items[0].getAttribute('meta') == 'yes') return alert(mt('_js_ds_tag_nometa')); var name = items[0].firstChild.nodeValue; var id = items[0].getAttribute('id'); if(byId('tgl_'+id)) return alert(mt('_tagv_double')); if(!byId('tagmod_newtags')) byId('tagtable').appendChild(tag('tr', {'class':'tagmod_cat', id:'tagmod_newtags'}, tag('td', {colspan:7}, mt('_tagv_newlyadded')))); var vote = tag('td', {'class':'tc_myvote', tgl_vote: 2}, ''); tglVoteBar(vote); var spoil = tag('td', {'class':'tc_myspoil', tgl_spoil: 0}, tglSpoilers[0]); ddInit(spoil, 'tagmod', tglSpoilDD); spoil.onclick = tglSpoilNext; var ismod = byClass(byId('tagtable').parentNode, 'td', 'tc_myover').length; byId('tagtable').appendChild(tag('tr', {id:'tgl_'+id}, tag('td', {'class':'tc_tagname'}, tag('a', {href:'/g'+id}, name)), vote, ismod ? tag('td', {'class':'tc_myover'}, ' ') : null, spoil, tag('td', {'class':'tc_allvote'}, ' '), tag('td', {'class':'tc_allspoil'}, ' '), tag('td', {'class':'tc_allwho'}, '') )); tglStripe(); tglSerialize(); }); } function tglStripe() { var l = byName(byId('tagtable'), 'tr'); for(var i=0; i V I S U A L N O V E L L I N K I N G (/r+/edit) */ function rvnLoad() { var vns = byId('vn').value.split('|||'); for(var i=0; i1; i++) rvnAdd(vns[i].split(',',2)[0], vns[i].split(',',2)[1]); rvnEmpty(); dsInit(byId('vn_input'), '/xml/vn.xml?q=', function(item, tr) { tr.appendChild(tag('td', {style:'text-align: right; padding-right: 5px'}, 'v'+item.getAttribute('id'))); tr.appendChild(tag('td', shorten(item.firstChild.nodeValue, 40))); }, function(item) { return 'v'+item.getAttribute('id')+':'+item.firstChild.nodeValue; }, rvnFormAdd ); byId('vn_add').onclick = rvnFormAdd; } 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'))) )); rvnStripe(); rvnEmpty(); } function rvnDel() { var tr = this; while(tr.nodeName.toLowerCase() != 'tr') tr = tr.parentNode; tr.parentNode.removeChild(tr); rvnEmpty(); rvnSerialize(); rvnStripe(); return false; } function rvnEmpty() { var tbl = byId('vn_tbl'); if(byName(tbl, 'tr').length < 1) tbl.appendChild(tag('tr', {id:'rvn_tr_none'}, tag('td', {colspan:2}, mt('_redit_form_vn_none')))); else if(byId('rvn_tr_none')) tbl.removeChild(byId('rvn_tr_none')); } function rvnStripe() { var l = byName(byId('vn_tbl'), 'tr'); for(var i=0; i P R O D U C E R L I N K I N G (/r+/edit) */ function rprLoad() { var ps = byId('producers').value.split('|||'); for(var i=0; i1; i++) { var val = ps[i].split(',',3); rprAdd(val[0], val[1], val[2]); } rprEmpty(); dsInit(byId('producer_input'), '/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; }, rprFormAdd ); byId('producer_add').onclick = rprFormAdd; } function rprAdd(id, role, name) { var roles = byId('producer_role').options; var rl = tag('select', {onchange:rprSerialize}); for(var i=0; i1; 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, * [ , * [ , , , , ], .. * ], .. * ] * Where: * human-readable title of the filter box * <category_name> human-readable name of the category. ignored if there's only one category * <fieldcode> code of this field, refers to the <field> in the filter format. Empty string for just a <tr> * <fieldname> human-readanle name of the field. Empty to not display a label. Space for always-enabled items (without checkbox) * <fieldcontents> tag() object, or an array of tag() objects * <fieldreadfunc> function reference. argument: <fieldcontents>; must return data to be used in the filter format * <fieldwritefunc> function reference, argument: <fieldcontents>, data from filter format; must update the contents with the passed data * * Filter string format: * <field>-<value1>~<value2>.<field2>-<value>.<field3>-<value1>~<value2> * Where: * <field> = [a-z0-9]+ * <value> = [a-zA-Z0-9_]+ and any UTF-8 characters not in the ASCII range * Escaping of the <value>: * "_<two-number-code>" * Where <two-number-code> is the decimal index to the following array: * _ <space> ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ ` { | } ~ * For boolean fields, the <value> is either 0 or 1. */ 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(); fil_cats = [ new Object ]; var p = tag('p', {'class':'browseopts'}); var c = tag('div', null); var idx = 0; for(var i=1; i<l.length; i++) { if(!l[i]) continue; idx++; // category link var a = tag('a', { href: '#', onclick: filSelectCat, fil_num: idx, fil_onshow:[] }, l[i][0]); p.appendChild(a); p.appendChild(tag(' ')); // category contents var t = tag('table', {'class':'formtable', fil_num: idx}, null); setClass(t, 'hidden', true); a.fil_t = t; for(var j=1; j<l[i].length; j++) { var fd = l[i][j]; var lab = typeof fd[1] == 'object' ? fd[1][0] : fd[1]; var f = tag('tr', {'class':'newfield', fil_code: fd[0], fil_contents: fd[2], fil_readfunc: fd[3], fil_writefunc: fd[4]}, fd[0] ? tag('td', {'class':'check'}, tag('input', {type:'checkbox', id:'fil_check_'+fd[0], 'class':fd[1]==' '?'hidden':'', name:'fil_check_'+fd[0], onclick: filSelectField })) : tag('td', null), fd[1] ? tag('td', {'class':'label'}, tag('label', {'for':'fil_check_'+fd[0]}, lab), typeof fd[1] == 'object' ? tag('b', fd[1][1]) : null ) : null, tag('td', {'class':'cont' }, fd[2])); if(fd[0]) fil_cats[0][fd[0]] = f; if(fd[5]) a.fil_onshow.push([ fd[5], f.fil_contents ]); t.appendChild(f); } c.appendChild(t); fil_cats[idx] = a; } addBody(tag('div', { id: 'fil_div', 'class':'hidden' }, tag('a', {href:'#', onclick:filShow, 'class':'close'}, mt('_js_close')), tag('h3', l[0]), p, tag('b', {'class':'ruler'}, null), c, tag('b', {'class':'ruler'}, null), tag('input', {type:'button', 'class':'submit', value: mt('_js_fil_apply'), onclick:function () { var f = byId('fil'); while(f.nodeName.toLowerCase() != 'form') f = f.parentNode; 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, tag('p', {id:'fil_savenote', 'class':'hidden'}, '') )); filSelectCat(1); byId('filselect').onclick = filShow; filDeSerialize(); } function filSaveDefault() { var but = this; var note = byId('fil_savenote'); setText(note, mt('_js_loading')); but.enabled = false; setClass(byId('fil_savenote'), 'hidden', false); var type = byId('filselect').href.match(/#r$/) ? 'release' : 'vn'; ajax('/xml/prefs.xml?formcode='+PREF_CODE+';key=filter_'+type+';value='+byId('fil').value, function (hr) { setText(note, mt('_js_fil_savenote')); but.enable = true; }); } function filSelectCat(n) { setClass(byId('fil_savenote'), 'hidden', true); n = this.fil_num ? this.fil_num : n; for(var i=1; i<fil_cats.length; i++) { setClass(fil_cats[i], 'optselected', i == n); setClass(fil_cats[i].fil_t, 'hidden', i != n); } for(var i=0; i<fil_cats[n].fil_onshow.length; i++) fil_cats[n].fil_onshow[i][0](fil_cats[n].fil_onshow[i][1]); return false } function filSelectField(obj) { var t = obj && obj.parentNode ? obj : this; setClass(byId('fil_savenote'), 'hidden', true); // update checkbox and label var o = t; while(o.nodeName.toLowerCase() != 'tr') o = o.parentNode; var c = byId('fil_check_'+o.fil_code); if(c != t) c.checked = true; if(hasClass(c, 'hidden')) c.checked = true; setClass(byName(o, 'label')[0], 'active', c.checked); // update category link while(o.nodeName.toLowerCase() != 'table') o = o.parentNode; var l = byName(o, 'input'); var n=0; for(var i=0; i<l.length; i++) if(l[i].type == 'checkbox' && l[i].id.substr(0, 10) == 'fil_check_' && !hasClass(l[i], 'hidden') && l[i].checked) n++; setClass(fil_cats[o.fil_num], 'active', n>0); // serialize filSerialize(); return true; } function filSerialize() { var num = 0; var values = {}; for(var f in fil_cats[0]) { if(!byId('fil_check_'+f).checked) continue; if(!hasClass(byId('fil_check_'+f), 'hidden')) num++; var v = fil_cats[0][f].fil_readfunc(fil_cats[0][f].fil_contents); var r = []; for(var h=0; h<v.length; h++) { var vs = (''+v[h]).split(''); r[h] = ''; // this isn't a very fast escaping method, blame JavaScript for inflexible search/replace support for(var i=0; i<vs.length; i++) { for(var j=0; j<fil_escape.length; j++) if(vs[i] == fil_escape[j]) break; r[h] += j == fil_escape.length ? vs[i] : '_'+(j<10?'0'+j:j); } } if(r.length > 0 && r[0] != '') values[fil_cats[0][f].fil_code] = r.join('~'); } if(!values['tag_inc']) delete values['tagspoil']; var l = []; for(var f in values) l.push(f+'-'+values[f]); byId('fil').value = l.join('.'); setText(byName(byId('filselect'), 'i')[1], num > 0 ? ' ('+num+')' : ''); } function filDeSerialize() { var d = byId('fil').value; var fs = d.split('.'); var f = new Object; for(var i=0; i<fs.length; i++) { var v = fs[i].split('-'); if(fil_cats[0][v[0]]) f[v[0]] = v[1]; } for(var fn in fil_cats[0]) if(!f[fn]) f[fn] = ''; for(var fn in f) { var c = byId('fil_check_'+fn); if(!c) continue; c.checked = f[fn] == '' ? false : true; var v = f[fn].split('~'); for(var i=0; i<v.length; i++) v[i] = v[i].replace(/_([0-9]{2})/g, function (a, e) { return fil_escape[Math.floor(e)] }); fil_cats[0][fn].fil_writefunc(fil_cats[0][fn].fil_contents, v); // not very efficient: filSelectField() does a lot of things that can be // batched after all fields have been updated, and in some cases the // writefunc() triggers the same filSelectField() as well filSelectField(c); } } function filShow() { var div = byId('fil_div'); var hid = !hasClass(div, 'hidden'); setClass(div, 'hidden', hid); setText(byName(byId('filselect'), 'i')[0], hid ? collapsed_icon : expanded_icon); setClass(byId('fil_savenote'), 'hidden', true); var o = this; ddx = ddy = 0; do { ddx += o.offsetLeft; ddy += o.offsetTop; } while(o = o.offsetParent); ddy += this.offsetHeight+2; ddx += (this.offsetWidth-div.offsetWidth)/2; div.style.left = ddx+'px'; div.style.top = ddy+'px'; return false; } 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++) { if(typeof opts[i][1] != 'object') s.appendChild(tag('option', {name: opts[i][0]}, opts[i][1])); else { var g = tag('optgroup', {label: opts[i][0]}); for(var j=1; j<opts[i].length; j++) g.appendChild(tag('option', {name: opts[i][j][0]}, opts[i][j][1])); s.appendChild(g); } } return [ c, lines > 1 ? [ n, mt('_js_fil_boolor') ] : n, s, function (c) { var l = []; for(var i=0; i<c.options.length; i++) if(c.options[i].selected) l.push(c.options[i].name); return l; }, function (c, f) { for(var i=0; i<c.options.length; i++) { for(var j=0; j<f.length; j++) if(c.options[i].name+'' == f[j]+'') // beware of JS logic: 0 == '', but '0' != '' break; c.options[i].selected = j != f.length; } } ]; } function filFOptions(c, n, opts, setfunc) { var p = tag('p', {'class':'opts', fil_val:opts[0][0]}); var sel = function (e) { var o = typeof e == 'string' ? e : this.fil_n; if(setfunc) o = setfunc(o); var l = byName(p, 'a'); for(var i=0; i<l.length; i++) setClass(l[i], 'tsel', l[i].fil_n+'' == o+''); p.fil_val = o; if(typeof e != 'string') filSelectField(p); return false }; for(var i=0; i<opts.length; i++) { p.appendChild(tag('a', {href:'#', fil_n: opts[i][0], onclick:sel}, opts[i][1])); if(i<opts.length-1) p.appendChild(tag('b', '|')); } return [ c, n, p, function (c) { return [ c.fil_val ] }, function (c, v) { sel(v[0]) } ]; } function filFTagInput(name, label) { 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), ' (', tag('a', {href:'#', onclick:function () { // a -> li -> ul -> div var ul = this.parentNode.parentNode; ul.removeChild(this.parentNode); filSelectField(ul.parentNode); return false } }, mt('_vnbrowse_tagrem')), ')' )); } var fetch = function(c) { var v = c.fil_val; var ul = byName(c, 'ul')[0]; var txt = byName(c, 'input')[0]; if(v == null) return; if(!v[0]) { setText(ul, ''); txt.disabled = false; txt.value = ''; return; } if(!visible) setText(ul, ''); var q = []; for(var i=0; i<v.length; i++) { q.push('id='+v[i]); if(!visible) addtag(ul, v[i]); } txt.value = mt('_js_loading'); txt.disabled = true; if(visible) ajax('/xml/tags.xml?'+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); txt.value = ''; txt.disabled = false; c.fil_val = null; }, 1); }; var input = tag('input', {type:'text', 'class':'text', style:'width:300px', onfocus:filSelectField}); var list = tag('ul', null); dsInit(input, '/xml/tags.xml?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 )); }, function(item, obj) { if(item.getAttribute('meta') == 'yes') alert(mt('_js_ds_tag_nometa')); else { addtag(byName(obj.parentNode, 'ul')[0], item.getAttribute('id'), item.firstChild.nodeValue); filSelectField(obj); } return ''; }, function(o) { filSelectField(o); false } ); return [ name, label, tag('div', list, input), function(c) { var v = []; var l = byName(c, 'li'); for(var i=0; i<l.length; i++) v.push(l[i].fil_id); return v; }, function(c,v) { c.fil_val = v; fetch(c) }, function(c) { visible = true; fetch(c); } ]; } function filReleases() { var types = release_types; for(var i=0; i<types.length; i++) // l10n /_rtype_.+/ types[i] = [ types[i], mt('_rtype_'+types[i]) ]; var ages = age_ratings; for(var i=0; i<ages.length; i++) ages[i] = [ ages[i], ages[i] == -1 ? mt('_minage_null') : ages[i] == 0 ? mt('_minage_all') : mt('_minage_age', ages[i]) ]; var lang = languages; for(var i=0; i<lang.length; i++) // l10n /_lang_.+/ lang[i] = [ lang[i], mt('_lang_'+lang[i]) ]; var plat = platforms; for(var i=0; i<plat.length; i++) // l10n /_plat_.+/ plat[i] = [ plat[i], mt('_plat_'+plat[i]) ]; var med = media; for(var i=0; i<med.length; i++) // l10n /_med_.+/ med[i] = [ med[i], mt('_med_'+med[i]) ]; var voi = voiced; for(var i=0; i<voi.length; i++) // l10n /_voiced_.+/ voi[i] = [ voi[i], mt('_voiced_'+voi[i]) ]; var ani = animated; for(var i=0; i<ani.length; i++) // l10n /_animated_.+/ ani[i] = [ ani[i], mt('_animated_'+ani[i]) ]; return [ mt('_rbrowse_fil_title'), [ mt('_rbrowse_general'), filFOptions('type', mt('_rbrowse_type'), types), filFOptions('patch', mt('_rbrowse_patch'), [ [1, mt('_rbrowse_patch_yes')], [0, mt('_rbrowse_patch_no')] ]), filFOptions('freeware', mt('_rbrowse_freeware'),[ [1, mt('_rbrowse_freeware_yes')], [0, mt('_rbrowse_freeware_no')] ]), filFOptions('doujin', mt('_rbrowse_doujin'), [ [1, mt('_rbrowse_doujin_yes')], [0, mt('_rbrowse_doujin_no')] ]), [ 'date_after', mt('_rbrowse_dateafter'), dateLoad(null, filSelectField), function (c) { return [c.date_val] }, dateSet ], [ 'date_before', mt('_rbrowse_datebefore'), dateLoad(null, filSelectField), function (c) { return [c.date_val] }, dateSet ], filFOptions('released', mt('_rbrowse_released'),[ [1, mt('_rbrowse_released_yes')], [0, mt('_rbrowse_released_no')] ]) ], [ mt('_rbrowse_minage'), filFSelect('minage', mt('_rbrowse_minage'), 15, ages) ], [ mt('_rbrowse_language'), filFSelect('lang', mt('_rbrowse_language'), 20, lang) ], [ mt('_rbrowse_olang'), filFSelect('olang', mt('_rbrowse_olang'), 20, lang) ], [ mt('_rbrowse_resolution'), filFSelect('resolution', mt('_rbrowse_resolution'), 15, resolutions) ], [ mt('_rbrowse_platform'), filFSelect('plat', mt('_rbrowse_platform'), 20, plat) ], [ mt('_rbrowse_medium'), filFSelect('med', mt('_rbrowse_medium'), 10, med) ], [ mt('_rbrowse_voiced'), filFSelect('voiced', mt('_rbrowse_voiced'), 5, voi) ], [ mt('_rbrowse_animation'), filFSelect('ani_story', mt('_rbrowse_ani_story'), 5, ani), filFSelect('ani_ero', mt('_rbrowse_ani_ero'), 5, ani) ] ]; } function filVN() { var lang = languages; for(var i=0; i<lang.length; i++) // l10n /_lang_.+/ lang[i] = [ lang[i], mt('_lang_'+lang[i]) ]; var plat = platforms; for(var i=0; i<plat.length; i++) // l10n /_plat_.+/ plat[i] = [ plat[i], mt('_plat_'+plat[i]) ]; var len = vn_lengths; for(var i=0; i<len.length; i++) // l10n /_vnlength_.+/ len[i] = [ len[i], mt('_vnlength_'+len[i]) ]; var ontagpage = location.pathname.indexOf('/v/') < 0; return [ mt('_vnbrowse_fil_title'), [ mt('_vnbrowse_general'), filFSelect( 'length', mt('_vnbrowse_length'), 6, len), filFOptions('hasani', mt('_vnbrowse_anime'), [[1, mt('_vnbrowse_anime_yes')],[0, mt('_vnbrowse_anime_no')]]) ], ontagpage ? [ mt('_vnbrowse_tags'), [ '', ' ', tag(mt('_vnbrowse_tagnothere')) ], ] : [ 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')), 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}) ], [ mt('_vnbrowse_language'), filFSelect('lang', mt('_vnbrowse_language'), 20, lang) ], [ mt('_vnbrowse_olang'), filFSelect('olang',mt('_vnbrowse_olang'), 20, lang) ], [ mt('_vnbrowse_platform'), filFSelect('plat', mt('_vnbrowse_platform'), 20, plat) ], PREF_CODE == '' ? null : [ mt('_vnbrowse_ul'), filFOptions('ul_notblack', mt('_vnbrowse_ul_notblack'), [[1, mt('_vnbrowse_ul_notblackmsg')]]), filFOptions('ul_onwish', mt('_vnbrowse_ul_onwish'), [[0, mt('_vnbrowse_ul_onwishno')],[1, mt('_vnbrowse_ul_onwishyes')]]), filFOptions('ul_voted', mt('_vnbrowse_ul_voted'), [[0, mt('_vnbrowse_ul_votedno')], [1, mt('_vnbrowse_ul_votedyes') ]]), filFOptions('ul_onlist', mt('_vnbrowse_ul_onlist'), [[0, mt('_vnbrowse_ul_onlistno')],[1, mt('_vnbrowse_ul_onlistyes')]]) ], ]; } if(byId('filselect')) filLoad(); /* M I S C S T U F F */ // search box { var i = byId('sq'); i.onfocus = function () { if(this.value == mt('_menu_emptysearch')) { this.value = ''; this.style.fontStyle = 'normal' } }; i.onblur = function () { if(this.value.length < 1) { this.value = mt('_menu_emptysearch'); this.style.fontStyle = 'italic' } }; } // VN Voting (/v+) if(byId('votesel')) { byId('votesel').onchange = function() { var s = this.options[this.selectedIndex].value; if(s == 1 && !confirm(mt('_vnpage_uopt_1vote'))) return; if(s == 10 && !confirm(mt('_vnpage_uopt_10vote'))) return; if(s) location.href = location.href.replace(/\.[0-9]+/, '')+'/vote?formcode='+this.name+';v='+s; }; } // Advanced search (/v/*) if(byId('advselect')) { byId('advselect').onclick = function() { var box = byId('advoptions'); var hidden = !hasClass(box, 'hidden'); setClass(box, 'hidden', hidden); setText(byName(this, 'i')[0], hidden ? collapsed_icon : expanded_icon); return false; }; } // NSFW VN image toggle (/v+) if(byId('nsfw_show')) { var msg = byId('nsfw_show'); var img = byId('nsfw_hid'); byName(msg, 'a')[0].onclick = function() { msg.style.display = 'none'; img.style.display = 'block'; return false; }; img.onclick = function() { msg.style.display = 'block'; img.style.display = 'none'; }; } // NSFW toggle for screenshots (/v+) if(byId('nsfwhide')) { byId('nsfwhide').onclick = function() { var shown = 0; var l = byClass(byId('screenshots'), 'a', 'scrlnk'); for(var i=0; i<l.length; i++) { if(hasClass(l[i], 'nsfw')) { var hidden = !hasClass(l[i], 'hidden'); setClass(l[i], 'hidden', hidden); if(!hidden) shown++; } else shown++; } setText(byId('nsfwshown'), shown); return false; }; } // VN Wishlist dropdown box (/v+) if(byId('wishsel')) { byId('wishsel').onchange = function() { if(this.selectedIndex != 0) location.href = location.href.replace(/\.[0-9]+/, '') +'/wish?formcode='+this.name+';s='+this.options[this.selectedIndex].value; }; } // Release & VN list dropdown box (/r+ and /v+) if(byId('listsel')) { byId('listsel').onchange = function() { if(this.selectedIndex != 0) location.href = location.href.replace(/\.[0-9]+/, '') +'/list?formcode='+this.name+';e='+this.options[this.selectedIndex].value; }; } // BBCode spoiler tags { var l = byClass('b', 'spoiler'); for(var i=0; i<l.length; i++) { l[i].onmouseover = function() { setClass(this, 'spoiler', false); setClass(this, 'spoiler_shown', true) }; l[i].onmouseout = function() { setClass(this, 'spoiler', true); setClass(this, 'spoiler_shown', false) }; } } // vndb.org domain check // (let's just keep this untranslatable, nobody cares anyway ^^) if(location.hostname != 'vndb.org') { addBody(tag('div', {id:'debug'}, tag('h2', 'This is not VNDB!'), 'The real VNDB is ', tag('a', {href:'http://vndb.org/'}, 'here'), '.' )); } // make some fields readonly when patch flag is set (/r+/edit) if(byId('jt_box_rel_geninfo')) { var func = function() { byId('doujin').disabled = byId('resolution').disabled = byId('voiced').disabled = byId('ani_story').disabled = byId('ani_ero').disabled = byId('patch').checked; }; func(); byId('patch').onclick = func; } // Batch edit dropdown box (/u+/wish and /u+/votes) if(byId('batchedit')) { byId('batchedit').onchange = function() { if(this.selectedIndex == 0) return true; var frm = this; while(frm.nodeName.toLowerCase() != 'form') frm = frm.parentNode; frm.submit(); }; } // collapse/expand row groups (/u+/list) if(byId('expandall')) { var table = byId('expandall'); while(table.nodeName.toLowerCase() != 'table') table = table.parentNode; var heads = byClass(table, 'td', 'collapse_but'); var allhid = false; var alltoggle = function() { allhid = !allhid; var l = byClass(table, 'tr', 'collapse'); for(var i=0; i<l.length; i++) { setClass(l[i], 'hidden', allhid); 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(heads[i], allhid ? collapsed_icon : expanded_icon); return false; } byId('expandall').onclick = alltoggle; alltoggle(); var singletoggle = function() { var l = byClass(table, 'tr', 'collapse_'+this.id); if(l.length < 1) return; var hid = !hasClass(l[0], 'hidden'); for(var i=0; i<l.length; i++) { setClass(l[i], 'hidden', hid); 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; } // set note input box (/u+/list) if(byId('not') && byId('vns')) byId('vns').onchange = function () { if(this.options[this.selectedIndex].value == 999) byId('not').value = prompt(mt('_rlist_setnote_prompt'), ''); return true; }; // expand/collapse release listing (/p+) if(byId('expandprodrel')) { var lnk = byId('expandprodrel'); setexpand = function() { var exp = !(getCookie('prodrelexpand') == 1); setText(lnk, exp ? mt('_js_collapse') : mt('_js_expand')); setClass(byId('prodrel'), 'collapse', !exp); }; setexpand(); lnk.onclick = function () { setCookie('prodrelexpand', getCookie('prodrelexpand') == 1 ? 0 : 1); setexpand(); return false; }; } // Language selector if(byId('lang_select')) { var d = byId('lang_select'); var curlang = byName(d, 'acronym')[0].className.substr(11, 2); ddInit(d, 'bottom', function(lnk) { var lst = tag('ul', null); for(var i=0; i<L10N_LANG.length; i++) { var ln = L10N_LANG[i]; var icon = tag('acronym', {'class':'icons lang '+ln[0]}, ' '); lst.appendChild(tag('li', {'class':'lang_selector'}, curlang == ln[0] ? tag('i', icon, mt('_lang_'+ln[0])) : tag('a', {href:'/setlang?lang='+ln[0]}, icon, ln[1]) )); } return lst; }); d.onclick = function() {return false}; } // "check all" checkbox { 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 && !hasClass(l[i], 'hidden')) l[i].checked = this.checked; }; var l = byClass('input', 'checkall'); for(var i=0; i<l.length; i++) if(l[i].type == 'checkbox') l[i].onclick = f; } // search tabs if(byId('searchtabs')) { var f = function() { var str = byId('q').value; if(str.length > 1) { if(this.href.indexOf('/g') >= 0) this.href += '/list'; this.href += '?q=' + encodeURIComponent(str); } return true; }; var l = byName(byId('searchtabs'), 'a'); for(var i=0; i<l.length; i++) l[i].onclick = f; } // spam protection on all forms setTimeout(function() { for(i=1; i<document.forms.length; i++) document.forms[i].action = document.forms[i].action.replace(/\/nospam\?/,''); }, 500);