summaryrefslogtreecommitdiff
path: root/data/script.js
diff options
context:
space:
mode:
Diffstat (limited to 'data/script.js')
-rw-r--r--data/script.js314
1 files changed, 295 insertions, 19 deletions
diff --git a/data/script.js b/data/script.js
index cdbac941..64ae4187 100644
--- a/data/script.js
+++ b/data/script.js
@@ -2,6 +2,7 @@
* date -> Date selector
* dd -> dropdown
* ds -> dropdown search
+ * fil -> Filter selector
* iv -> image viewer
* jt -> Javascript Tabs
* med -> Release media selector
@@ -539,7 +540,7 @@ var date_years = [];
var date_months = [];
var date_days = [];
-function dateLoad(obj) {
+function dateLoad(obj, serfunc) {
/* load the arrays */
var i;
date_years = [ [ 0, mt('_js_date_year') ], [ 9999, 'TBA' ] ];
@@ -554,34 +555,49 @@ function dateLoad(obj) {
for(var i=1; i<=31; i++)
date_days[date_days.length] = [ i, i ];
- /* get current value */
- var val = Math.floor(obj.value) || 0;
- val = [ Math.floor(val/10000), Math.floor(val/100)%100, val%100 ];
-
/* create elements */
- for(var i=0; i<date_years.length; i++)
- if(val[0] == date_years[i][0]) { val[0] = i; break };
- var year = tag('b', {'class':'datepart', date_sel: val[0], date_lst:date_years, date_cnt:10},
+ var year = tag('b', {'class':'datepart', date_sel: 0, date_lst:date_years, date_cnt:10},
tag('i', expanded_icon),
- tag('b', date_years[val[0]][1])
+ tag('b', date_years[0][1])
);
ddInit(year, 'bottom', dateDD);
- val[1] = val[1] == 99 ? 0 : val[1];
- var month = tag('b', {'class':'datepart', date_sel: val[1], date_lst:date_months, date_cnt:7},
+ var month = tag('b', {'class':'datepart', date_sel: 0, date_lst:date_months, date_cnt:7},
tag('i', expanded_icon),
- tag('b', date_months[val[1]][1])
+ tag('b', date_months[0][1])
);
ddInit(month, 'bottom', dateDD);
- val[2] = val[2] == 99 ? 0 : val[2];
- var day = tag('b', {'class':'datepart', date_sel: val[2], date_lst:date_days, date_cnt:10},
+ var day = tag('b', {'class':'datepart', date_sel: 0, date_lst:date_days, date_cnt:10},
tag('i', expanded_icon),
- tag('b', date_days[val[2]][1])
+ tag('b', date_days[0][1])
);
ddInit(day, 'bottom', dateDD);
- obj.parentNode.insertBefore(tag('div', {date_obj: obj}, year, month, day), obj);
+ 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 ];
+ var l = byClass(div, 'b', 'datepart');
+ // year
+ for(var i=0; i<date_years.length; i++)
+ if(val[0] == date_years[i][0]) { val[0] = i; break };
+ l[0].date_sel = val[0];
+ setText(byName(l[0], 'b')[0], date_years[val[0]][1]);
+ // month
+ val[1] = val[1] == 99 ? 0 : val[1];
+ l[1].date_sel = val[1];
+ setText(byName(l[1], 'b')[0], date_months[val[1]][1]);
+ // day
+ val[2] = val[2] == 99 ? 0 : val[2];
+ l[2].date_sel = val[2];
+ setText(byName(l[2], 'b')[0], date_days[val[2]][1]);
+ dateSerialize(div.childNodes[0], true);
}
function dateDD(lnk) {
@@ -603,7 +619,7 @@ function dateDD(lnk) {
return d;
}
-function dateSerialize(div) {
+function dateSerialize(div, nonotify) {
var div = div.parentNode;
var sel = byClass(div, 'b', 'datepart');
var val = [
@@ -611,7 +627,11 @@ function dateSerialize(div) {
date_months[sel[1].date_sel][0],
date_days[sel[2].date_sel][0],
];
- div.date_obj.value = val[0] == 0 ? 0 : val[0] == 9999 ? 99999999 : val[0]*10000+val[1]*100+(val[1]==99?99:val[2]);
+ div.date_val = val[0] == 0 ? 0 : val[0] == 9999 ? 99999999 : val[0]*10000+val[1]*100+(val[1]==99?99:val[2]);
+ if(div.date_obj)
+ div.date_obj.value = div.date_val;
+ if(!nonotify && div.date_serfunc)
+ div.date_serfunc(div);
}
{
@@ -1745,6 +1765,262 @@ if(byId('prodrelations'))
+/* F I L T E R S Y S T E M */
+
+
+/* Filter box definition:
+ * [ <title>,
+ * [ <category_name>,
+ * [ <fieldcode>, <fieldname>, <fieldcontents>, <fieldreadfunc>, <fieldwritefunc> ], ..
+ * ], ..
+ * ]
+ * Where:
+ * <title> 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
+ * <fieldname> human-readanle name of the field. Empty to not display a label
+ * <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 = filReleases();
+ fil_cats = [ new Object ];
+
+ var p = tag('p', {'class':'browseopts'});
+ var c = tag('div', null);
+ for(var i=1; i<l.length; i++) {
+ // category link
+ var a = tag('a', { href: '#', onclick: filSelectCat, fil_num: i }, l[i][0]);
+ p.appendChild(a);
+ p.appendChild(tag(' '));
+
+ // category contents
+ var t = tag('table', {'class':'formtable', fil_num: i}, null);
+ setClass(t, 'hidden', true);
+ a.fil_t = t;
+ for(var j=1; j<l[i].length; j++) {
+ var fd = l[i][j];
+ var f = tag('tr', {'class':'newfield', fil_code: fd[0], fil_contents: fd[2], fil_readfunc: fd[3], fil_writefunc: fd[4]},
+ tag('td', {'class':'check'}, tag('input', {type:'checkbox', id:'fil_check_'+fd[0], name:'fil_check_'+fd[0], onclick: filSelectField })),
+ fd[1] ? tag('td', {'class':'label'}, tag('label', {'for':'fil_check_'+fd[0]}, fd[1])) : '',
+ tag('td', {'class':'cont' }, fd[2]));
+ fil_cats[0][fd[0]] = f;
+ t.appendChild(f);
+ }
+ c.appendChild(t);
+
+ fil_cats[i] = a;
+ }
+
+ addBody(tag('div', { id: 'fil_div', 'class':'hidden' },
+ tag('h3', l[0]),
+ p,
+ tag('b', {'class':'ruler'}, null),
+ c,
+ tag('b', {'class':'ruler'}, null),
+ tag('input', {type:'button', 'class':'submit', value: mt('_rbrowse_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('_rbrowse_reset'), onclick:function () { byId('fil').value = ''; filDeSerialize()} })
+ ));
+ filSelectCat(1);
+ filDeSerialize();
+ byId('filselect').onclick = filShow;
+}
+
+function filSelectCat(n) {
+ 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);
+ }
+ return false
+}
+
+function filSelectField(obj) {
+ var t = obj.parentNode ? obj : this;
+ // 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;
+ 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_' && l[i].checked)
+ n++;
+ setClass(fil_cats[o.fil_num], 'active', n>0);
+
+ // serialize
+ filSerialize();
+ return true;
+}
+
+function filSerialize() {
+ var l = [];
+ for(var f in fil_cats[0]) {
+ if(!byId('fil_check_'+f).checked)
+ continue;
+ var v = fil_cats[0][f].fil_readfunc(fil_cats[0][f].fil_contents);
+ var r = [];
+ for(var h=0; h<v.length; h++) {
+ v[h] = (''+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<v[h].length; i++) {
+ for(var j=0; j<fil_escape.length; j++)
+ if(v[h][i] == fil_escape[j])
+ break;
+ r[h] += j == fil_escape.length ? v[h][i] : '_'+(j<10?'0'+j:j);
+ }
+ }
+ if(r.length > 0 && r[0] != '')
+ l.push(fil_cats[0][f].fil_code+'-'+r.join(','));
+ }
+ byId('fil').value = l.join('.');
+ var cnt = byName(byId('filselect'), 'i')[1];
+ setText(cnt, l.length > 0 ? ' ('+l.length+')' : '');
+}
+
+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);
+ c.checked = f[fn] == '' ? false : true;
+ fil_cats[0][fn].fil_writefunc(fil_cats[0][fn].fil_contents, f[fn].split(','));
+ // 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);
+
+ 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, 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 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]) ];
+ return [
+ mt('_rbrowse_fil_title'),
+ [ mt('_rbrowse_general'),
+ filFSelect('type', mt('_rbrowse_type'), 1, types),
+ filFSelect('patch', mt('_rbrowse_patch'), 1, [ [1, mt('_rbrowse_patch_yes')], [0, mt('_rbrowse_patch_no')] ]),
+ filFSelect('freeware', mt('_rbrowse_freeware'),1, [ [1, mt('_rbrowse_freeware_yes')], [0, mt('_rbrowse_freeware_no')] ]),
+ filFSelect('doujin', mt('_rbrowse_doujin'), 1, [ [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 ]
+ ],
+ [ mt('_rbrowse_minage'), filFSelect('minage', mt('_rbrowse_minage'), 15, ages) ],
+ [ mt('_rbrowse_language'), filFSelect('lang', mt('_rbrowse_language'), 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) ]
+ ];
+}
+
+if(byId('filselect'))
+ filLoad();
+
+
+
+
/* M I S C S T U F F */
// search box
@@ -1777,7 +2053,7 @@ if(byId('votesel')) {
};
}
-// Advanced search (/v/*, /r)
+// Advanced search (/v/*)
if(byId('advselect')) {
byId('advselect').onclick = function() {
var box = byId('advoptions');