summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/js/lib.js12
-rw-r--r--data/js/vnscr.js282
-rw-r--r--data/lang.txt12
-rw-r--r--lib/VNDB/DB/VN.pm2
-rw-r--r--lib/VNDB/Handler/VNEdit.pm50
-rw-r--r--static/f/blank.css0
6 files changed, 169 insertions, 189 deletions
diff --git a/data/js/lib.js b/data/js/lib.js
index b01a93c8..675f2baa 100644
--- a/data/js/lib.js
+++ b/data/js/lib.js
@@ -3,10 +3,10 @@ window.collapsed_icon = '▸';
var ajax_req;
-window.ajax = function(url, func, async) {
+window.ajax = function(url, func, async, body) {
if(!async && ajax_req)
ajax_req.abort();
- var req = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
+ var req = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
if(!async)
ajax_req = req;
req.onreadystatechange = function() {
@@ -16,9 +16,11 @@ window.ajax = function(url, func, async) {
return alert('Whoops, error! :(');
func(req);
};
- url += (url.indexOf('?')>=0 ? ';' : '?')+(Math.floor(Math.random()*999)+1);
- req.open('GET', url, true);
- req.send(null);
+ if(!body)
+ url += (url.indexOf('?')>=0 ? ';' : '?')+(Math.floor(Math.random()*999)+1);
+ req.open(body ? 'POST' : 'GET', url, true);
+ req.send(body);
+ return req;
};
diff --git a/data/js/vnscr.js b/data/js/vnscr.js
index c62eb982..21b1ba74 100644
--- a/data/js/vnscr.js
+++ b/data/js/vnscr.js
@@ -1,134 +1,135 @@
-var scrRel = [ [ 0, mt('_vnedit_scr_selrel') ] ];
-var scrStaticURL;
-var scrUplNr = 0;
-var scrDefRel;
-
-function scrLoad() {
- // get scrRel and scrStaticURL
- var rel = byId('scr_rel');
- scrStaticURL = rel.className;
- for(var i=0; i<rel.options.length; i++)
- scrRel[scrRel.length] = [ rel.options[i].value, getText(rel.options[i]) ];
- rel.parentNode.removeChild(rel);
- if(scrRel.length <= 2)
- scrRel.shift();
- scrDefRel = scrRel[0][0];
-
- // load the current screenshots
- var scr = byId('screenshots').value.split(' ');
- var siz = byId('screensizes').value.split(' ');
- for(i=0; i<scr.length && scr[i].length>1; i++) {
- var r = scr[i].split(',');
- var s = siz[i].split(',');
- scrSet(scrAdd(r[0], r[1], r[2]), s[0], s[1]);
+var rels;
+var defRid = 0;
+var staticUrl;
+
+function init() {
+ var data = jsonParse(getText(byId('screendata'))) || {};
+ rels = data.rel;
+ rels.unshift([ 0, mt('_vnedit_scr_selrel') ]);
+ staticUrl = data.staticurl;
+
+ var scr = jsonParse(byId('screenshots').value) || {};
+ for(i=0; i<scr.length; i++) {
+ var r = scr[i];
+ var s = data.size[r.id];
+ loaded(add(r.nsfw, r.rid), r.id, s[0], s[1]);
}
- ivInit();
- scrLast();
- scrSetSubmit();
-}
-
-function scrSetSubmit() {
var frm = byId('screenshots');
while(frm.nodeName.toLowerCase() != 'form')
frm = frm.parentNode;
- onSubmit(frm, function() {
- var loading = 0;
- var norelease = 0;
- var l = byName(byId('scr_table'), 'tr');
- for(var i=0; i<l.length-1; i++) {
- var rel = byName(l[i], 'select')[0];
- if(l[i].scr_status > 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;
- }
- return true;
- });
+ onSubmit(frm, handleSubmit);
+
+ addLast();
+ ivInit();
}
-function scrURL(id, t) {
- return scrStaticURL+'/s'+t+'/'+(id%100<10?'0':'')+(id%100)+'/'+id+'.jpg';
+function handleSubmit() {
+ var loading = 0;
+ var norelease = 0;
+
+ var r = [];
+ var l = byName(byId('scr_table'), 'tr');
+ for(var i=0; i<l.length-1; i++)
+ if(l[i].scr_loading)
+ loading = 1;
+ else if(l[i].scr_rid == 0)
+ norelease = 1;
+ else
+ r.push({ rid: l[i].scr_rid, nsfw: l[i].scr_nsfw, id: l[i].scr_id });
+
+ if(loading)
+ alert(mt('_vnedit_scr_frmloading'));
+ else if(norelease)
+ alert(mt('_vnedit_scr_frmnorel'));
+ else
+ byId('screenshots').value = JSON.stringify(r);
+ return !loading && !norelease;
}
-function scrAdd(id, nsfw, rel) {
- // tr.scr_status = 0: done, 1: uploading
+function genRels(sel) {
+ var r = tag('select', {'class':'scr_relsel'});
+ for(var i=0; i<rels.length; i++)
+ r.appendChild(tag('option', {value: rels[i][0], selected: rels[i][0] == sel}, rels[i][1]));
+ return r;
+}
+
+function URL(id, t) {
+ return staticUrl+'/s'+t+'/'+(id%100<10?'0':'')+(id%100)+'/'+id+'.jpg';
+}
- var tr = tag('tr', { id:'scr_tr_'+id, scr_id: id, scr_status: 1, scr_rel: rel, scr_nsfw: nsfw},
+// Need to run addLast() after this function
+function add(nsfw, rid) {
+ var tr = tag('tr', { scr_id: 0, scr_loading: 1, scr_rid: rid, scr_nsfw: nsfw?1:0},
tag('td', { 'class': 'thumb'}, mt('_js_loading')),
tag('td',
tag('b', mt('_vnedit_scr_uploading')),
tag('br', null),
- id ? null : mt('_vnedit_scr_upl_msg'),
+ mt('_vnedit_scr_upl_msg'),
tag('br', null),
- id ? null : tag('a', {href:'#', onclick:scrDel}, mt('_vnedit_scr_cancel'))
+ tag('a', {href:'#', onclick:del}, mt('_vnedit_scr_cancel'))
)
);
byId('scr_table').appendChild(tr);
return tr;
}
-function scrSet(tr, width, height) {
- var dim = width+'x'+height;
- tr.scr_status = 0;
-
- // image
- setContent(byName(tr, 'td')[0],
- tag('a', {href: scrURL(tr.scr_id, 'f'), rel:'iv:'+dim+':edit'},
- tag('img', {src: scrURL(tr.scr_id, 't')})
- )
- );
-
- // check full resolution with the list of DB-defined resolutions
- var odd = true;
+function oddDim(dim) {
if(dim == '256x384') // special-case NDS resolution (not in the DB)
- odd = false;
- for(var j=0; j<VARS.resolutions.length && odd; j++) {
+ return false;
+ for(var j=0; j<VARS.resolutions.length; j++) {
if(typeof VARS.resolutions[j][1] != 'object') {
if(VARS.resolutions[j][0] == dim)
- odd = false;
+ return false;
} else {
for(var k=1; k<VARS.resolutions[j].length; k++)
if(VARS.resolutions[j][k][1] == dim)
- odd = false;
+ return false;;
}
}
+ return true;
+}
- // content
- var rel = tag('select', {onchange: scrSerialize, 'class':'scr_relsel'});
- for(var j=0; j<scrRel.length; j++)
- rel.appendChild(tag('option', {value: scrRel[j][0], selected: tr.scr_rel == scrRel[j][0]}, scrRel[j][1]));
- var nsfwid = 'scr_sfw_'+tr.scr_id;
+// Need to run ivInit() after this function
+function loaded(tr, id, width, height) {
+ var dim = width+'x'+height;
+ tr.id = 'scr_tr_'+id;
+ tr.scr_id = id;
+ tr.scr_loading = 0;
+
+ setContent(byName(tr, 'td')[0],
+ tag('a', {href: URL(tr.scr_id, 'f'), rel:'iv:'+dim+':edit'},
+ tag('img', {src: URL(tr.scr_id, 't')})
+ )
+ );
+
+ var rel = genRels(tr.scr_rid);
+ rel.onchange = function() { tr.scr_rid = this.options[this.selectedIndex].value };
+
+ var nsfwid = 'scr_nsfw_'+id;
setContent(byName(tr, 'td')[1],
- tag('b', mt('_vnedit_scr_id', tr.scr_id)),
- ' (', tag('a', {href: '#', onclick:scrDel}, mt('_js_remove')), ')',
+ tag('b', mt('_vnedit_scr_id', id)),
+ ' (', tag('a', {href: '#', onclick:del}, 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,
+ oddDim(dim) ? tag('b', {'class':'standout', 'style':'font-weight: bold'}, ' '+mt('_vnedit_scr_nonstandard')) : null,
tag('br', null),
tag('br', null),
- tag('input', {type:'checkbox', onclick:scrSerialize, id:nsfwid, name:nsfwid, checked: tr.scr_nsfw>0, 'class':'scr_nsfw'}),
+ tag('input', {type:'checkbox', name:nsfwid, id:nsfwid, checked: tr.scr_nsfw!=0, onclick: function() { tr.scr_nsfw = this.checked?1:0 }, 'class':'scr_nsfw'}),
tag('label', {'for':nsfwid}, mt('_vnedit_scr_nsfw')),
tag('br', null),
rel
);
}
-function scrLast() {
+function addLast() {
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; j<scrRel.length; j++)
- rel.appendChild(tag('option', {value: scrRel[j][0], selected: scrDefRel == scrRel[j][0]}, scrRel[j][1]));
+ var rel = genRels(defRid);
+ rel.onchange = function() { defRid = this.options[this.selectedIndex].value };
+ rel.id = 'scradd_relsel';
byId('scr_table').appendChild(tag('tr', {id:'scr_last'},
tag('td', {'class': 'thumb'}),
@@ -143,91 +144,60 @@ function scrLast() {
tag('br', null),
rel,
tag('br', null),
- tag('input', {name:'scr_upload', id:'scr_upload', type:'file', 'class':'text'}),
+ tag('input', {name:'scr_upload', id:'scr_upload', type:'file', 'class':'text', multiple:true}),
tag('br', null),
- tag('input', {type:'button', value:mt('_vnedit_scr_addbut'), 'class':'submit', onclick:scrUpload})
+ tag('input', {type:'button', value:mt('_vnedit_scr_addbut'), 'class':'submit', onclick:upload})
)
));
}
-function scrDel(what) {
- var tr = what && what.scr_status != null ? what : this;
- while(tr.nodeName.toLowerCase() != 'tr')
+function del(what) {
+ var tr = what && what.scr_id != null ? what : this;
+ while(tr.scr_id == null)
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));
+ if(tr.scr_ajax)
+ tr.scr_ajax.abort();
byId('scr_table').removeChild(tr);
- scrSerialize();
- scrLast();
+ addLast();
ivInit();
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);
+function uploadFile(f) {
+ var tr = add(0, defRid);
+ var fname = f.name;
+ var frm = new FormData();
+ frm.append('file', f);
+ tr.scr_ajax = ajax('/xml/screenshots.xml', function(hr) {
+ tr.scr_ajax = null;
+ var img = hr.responseXML.getElementsByTagName('image')[0];
+ var id = img.getAttribute('id');
+ if(id < 0) {
+ alert(fname + ":\n" + (id == -1 ? mt('_vnedit_scr_errformat') : mt('_vnedit_scr_errempty')));
+ del(tr);
} else {
- tr.id = 'scr_tr_'+tr.scr_id;
- scrSet(tr, fr.window.document.getElementsByTagName('image')[0].getAttribute('width'), fr.window.document.getElementsByTagName('image')[0].getAttribute('height'));
- scrSerialize();
+ loaded(tr, id, img.getAttribute('width'), img.getAttribute('height'));
ivInit();
}
- }
-
- tr.scr_upl = null;
- /* remove the <div> in a timeout, otherwise some browsers think the page is still loading */
- setTimeout(function() { ifr.parentNode.parentNode.removeChild(ifr.parentNode) }, 1000);
+ }, true, frm);
}
-function scrSerialize() {
- var r = [];
- var l = byName(byId('scr_table'), 'tr');
- for(var i=0; i<l.length-1; i++)
- if(l[i].scr_status == 0)
- r[r.length] = [
- l[i].scr_id,
- byClass(l[i], 'input', 'scr_nsfw')[0].checked ? 1 : 0,
- scrRel[byClass(l[i], 'select', 'scr_relsel')[0].selectedIndex][0]
- ].join(',');
- byId('screenshots').value = r.join(' ');
+function upload() {
+ var files = byId('scr_upload').files;
+
+ if(files.length < 1) {
+ alert(mt('_vnedit_scr_errempty'));
+ return false;
+ } else if(files.length + byName(byId('scr_table'), 'tr').length - 1 > 10) {
+ alert(mt('_vnedit_scr_errtoomany'));
+ return false;
+ }
+
+ for(var i=0; i<files.length; i++)
+ uploadFile(files[i]);
+ addLast();
+ return false;
}
-if(byId('jt_box_vn_scr') && byId('scr_table'))
- scrLoad();
+if(byId('jt_box_vn_scr'))
+ init();
diff --git a/data/lang.txt b/data/lang.txt
index 1fcc2103..ccfee14c 100644
--- a/data/lang.txt
+++ b/data/lang.txt
@@ -14501,6 +14501,18 @@ uk : Помилка завантаження!
it : Caricamento fallito!
Nessun file selezionato, o un file vuoto?
+:_vnedit_scr_errtoomany
+en : Too many files selected. The total number of screenshots may not exceed 10.
+ru*:
+cs*:
+hu*:
+nl*:
+de*:
+es*:
+tr*:
+uk*:
+it*:
+
# VN Relation graph page (/v+/rg)
diff --git a/lib/VNDB/DB/VN.pm b/lib/VNDB/DB/VN.pm
index d3b37315..54c410b5 100644
--- a/lib/VNDB/DB/VN.pm
+++ b/lib/VNDB/DB/VN.pm
@@ -239,7 +239,7 @@ sub dbVNRevisionInsert {
if($o->{screenshots}) {
$self->dbExec('DELETE FROM edit_vn_screenshots');
my $q = join ',', map '(?, ?, ?)', @{$o->{screenshots}};
- my @val = map +($_->[0], $_->[1]?1:0, $_->[2]), @{$o->{screenshots}};
+ my @val = map +($_->{id}, $_->{nsfw}?1:0, $_->{rid}), @{$o->{screenshots}};
$self->dbExec("INSERT INTO edit_vn_screenshots (scr, nsfw, rid) VALUES $q", @val) if @val;
}
diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index b1e3a548..01a33241 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -99,7 +99,10 @@ sub edit {
],
anime => join(' ', sort { $a <=> $b } map $_->{id}, @{$v->{anime}}),
vnrelations => join('|||', map $_->{relation}.','.$_->{id}.','.($_->{official}?1:0).','.$_->{title}, sort { $a->{id} <=> $b->{id} } @{$v->{relations}}),
- screenshots => join(' ', map sprintf('%d,%d,%d', $_->{id}, $_->{nsfw}?1:0, $_->{rid}), @{$v->{screenshots}}),
+ screenshots => json_encode [
+ map +{ id => $_->{id}, nsfw => $_->{nsfw}?1:0, rid => $_->{rid} },
+ sort { $a->{id} <=> $b->{id} } @{$v->{screenshots}}
+ ]
);
my $frm;
@@ -128,7 +131,11 @@ sub edit {
{ field => 'note', required => 0, maxlength => 250, default => '' },
]},
{ post => 'vnrelations', required => 0, default => '', maxlength => 5000 },
- { post => 'screenshots', required => 0, default => '', maxlength => 1000 },
+ { post => 'screenshots', required => 0, template => 'json', json_fields => [
+ { field => 'id', required => 1, template => 'id' },
+ { field => 'rid', required => 1, template => 'id' },
+ { field => 'nsfw', required => 1, template => 'uint', enum => [0,1] },
+ ]},
{ post => 'editsum', required => !$nosubmit, template => 'editsum' },
{ post => 'ihid', required => 0 },
{ post => 'ilock', required => 0 },
@@ -178,7 +185,7 @@ sub edit {
# 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} ];
- my $screenshots = [ map /^[0-9]+,[01],[0-9]+$/ ? [split /,/] : (), split / +/, $frm->{screenshots} ];
+ my $screenshots = json_decode $frm->{screenshots};
$frm->{ihid} = $frm->{ihid}?1:0;
$frm->{ilock} = $frm->{ilock}?1:0;
@@ -187,7 +194,7 @@ sub edit {
$frm->{anime} = join ' ', sort { $a <=> $b } keys %$anime;
$frm->{vnrelations} = join '|||', map $_->[0].','.$_->[1].','.($_->[2]?1:0).','.$_->[3], sort { $a->[1] <=> $b->[1]} @{$relations};
$frm->{img_nsfw} = $frm->{img_nsfw} ? 1 : 0;
- $frm->{screenshots} = join ' ', map sprintf('%d,%d,%d', $_->[0], $_->[1]?1:0, $_->[2]), sort { $a->[0] <=> $b->[0] } @$screenshots;
+ $frm->{screenshots} = json_encode [ sort { $a->{id} <=> $b->{id} } @$screenshots ];
$frm->{credits} = json_encode \@credits;
$frm->{seiyuu} = json_encode \@seiyuu;
@@ -420,13 +427,15 @@ sub _form {
[ static => nolabel => 1, content => mt '_vnedit_scrnorel' ],
) : (
[ hidden => short => 'screenshots' ],
- [ hidden => short => 'screensizes', value => do {
- # Current screenshot resolutions, for use by Javascript
- my @scr = map /^(\d+),/?$1:(), split / /, $frm->{screenshots};
- my %scr = map +($_->{id}, "$_->{width},$_->{height}"), @scr ? @{$self->dbScreenshotGet(\@scr)} : ();
- join ' ', map $scr{$_}, @scr;
- }],
[ static => nolabel => 1, content => sub {
+ my @scr = map $_->{id}, @{ json_decode $frm->{screenshots} };
+ my %scr = map +($_->{id}, [ $_->{width}, $_->{height}]), @scr ? @{$self->dbScreenshotGet(\@scr)} : ();
+ my @rels = map [ $_->{id}, sprintf '[%s] %s (r%d)', join(',', @{$_->{languages}}), $_->{title}, $_->{id} ], @$r;
+ script_json screendata => {
+ size => \%scr,
+ rel => \@rels,
+ staticurl => $self->{url_static},
+ };
div class => 'warning';
lit mt '_vnedit_scrmsg';
end;
@@ -434,9 +443,6 @@ sub _form {
table class => 'stripe';
tbody id => 'scr_table', '';
end;
- Select id => 'scr_rel', class => $self->{url_static};
- option value => $_->{id}, sprintf '[%s] %s (r%d)', join(',', @{$_->{languages}}), $_->{title}, $_->{id} for (@$r);
- end;
}],
)]
@@ -504,24 +510,15 @@ sub vnxml {
# handles uploading screenshots and fetching information about them
sub scrxml {
my $self = shift;
- return $self->htmlDenied if !$self->authCan('edit');
- $self->resHeader('Content-type' => 'text/xml; charset=UTF-8');
-
- # fetch information about screenshots
- die "This page can only be accessed as POST\n" if $self->reqMethod ne 'POST';
+ return $self->htmlDenied if !$self->authCan('edit') || $self->reqMethod ne 'POST';
# upload new screenshot
- my $num = $self->formValidate({get => 'upload', template => 'uint'});
- return $self->resNotFound if $num->{_err};
- my $param = "scr_upl_file_$num->{upload}";
-
- # check for simple errors
my $id = 0;
- my $imgdata = $self->reqUploadRaw($param);
+ my $imgdata = $self->reqUploadRaw('file');
$id = -2 if !$imgdata;
$id = -1 if !$id && $imgdata !~ /^(\xff\xd8|\x89\x50)/; # JPG or PNG headers
- # no error? save and let Multi process it
+ # no error? process it
my($ow, $oh);
if(!$id) {
my $im = Image::Magick->new;
@@ -546,9 +543,8 @@ sub scrxml {
chmod 0666, $fn;
}
+ $self->resHeader('Content-type' => 'text/xml; charset=UTF-8');
xml;
- # blank stylesheet because some browsers don't allow JS access otherwise
- lit qq|<?xml-stylesheet href="$self->{url_static}/f/blank.css" type="text/css" ?>|;
tag 'image', id => $id, $id > 0 ? (width => $ow, height => $oh) : (), undef;
}
diff --git a/static/f/blank.css b/static/f/blank.css
deleted file mode 100644
index e69de29b..00000000
--- a/static/f/blank.css
+++ /dev/null