summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2009-10-04 10:08:52 +0200
committerYorhel <git@yorhel.nl>2009-10-04 10:08:52 +0200
commitbad759e90cae690cc4ccb36aa388d8157f5aeb4a (patch)
treec4382ff621c3f16ee6180f03556b3bb22938bfeb
parent8569df99347d81a553933bff3a1530e4330b6165 (diff)
JS: Moved and rewrote VN relations editor
+ Some fixes and improvements in the dropdown search + Renamed 'relations' field to 'vnrelations', as other relations are going to be implemented as well New relation editor code is somewhat smaller than the old, mostly thanks to the tag() function. Also tried to make things less error-prone and easier to maintain by referencing things using self-explainable class names instead of the ordering of the HTML tags.
-rw-r--r--data/style.css12
-rw-r--r--lib/VNDB/Handler/VNEdit.pm20
-rw-r--r--static/f/forms.js166
-rw-r--r--static/f/script.js130
4 files changed, 144 insertions, 184 deletions
diff --git a/data/style.css b/data/style.css
index 94a47a72..06b68833 100644
--- a/data/style.css
+++ b/data/style.css
@@ -729,12 +729,12 @@ a.addnew {
#jt_box_vn_rel table { margin-bottom: 10px; }
#jt_box_vn_rel h2 { margin: 0 0 3px 0px; }
#jt_box_vn_rel td { padding: 1px 2px; vertical-align: middle; }
-#jt_box_vn_rel td.tc1 { width: 300px; text-align: right }
-#jt_box_vn_rel td.tc2 { width: 170px; white-space: nowrap }
-#jt_box_vn_rel td.tc3 { width: 200px; }
-#jt_box_vn_rel td.tc4 { width: 40px; text-align: right }
-#jt_box_vn_rel td.tc1 input { width: 280px; }
-#jt_box_vn_rel td.tc2 select { width: 130px; }
+#jt_box_vn_rel td.tc_vn { width: 300px; text-align: right }
+#jt_box_vn_rel td.tc_rel { width: 170px; white-space: nowrap }
+#jt_box_vn_rel td.tc_title { width: 200px; }
+#jt_box_vn_rel td.tc_add { width: 40px; text-align: right }
+#jt_box_vn_rel td.tc_vn input { width: 280px; }
+#jt_box_vn_rel td.tc_rel select { width: 130px; }
#ds_box {
border: 1px solid $border$;
diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index 591e24a6..e618b360 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -28,7 +28,7 @@ sub edit {
my %b4 = !$vid ? () : (
(map { $_ => $v->{$_} } qw|title original desc alias length l_wp l_encubed l_renai l_vnn img_nsfw|),
anime => join(' ', sort { $a <=> $b } map $_->{id}, @{$v->{anime}}),
- relations => join('|||', map $_->{relation}.','.$_->{id}.','.$_->{title}, sort { $a->{id} <=> $b->{id} } @{$v->{relations}}),
+ vnrelations => join('|||', map $_->{relation}.','.$_->{id}.','.$_->{title}, sort { $a->{id} <=> $b->{id} } @{$v->{relations}}),
screenshots => join(' ', map sprintf('%d,%d,%d', $_->{id}, $_->{nsfw}?1:0, $_->{rid}), @{$v->{screenshots}}),
);
@@ -46,7 +46,7 @@ sub edit {
{ name => 'l_vnn', required => 0, default => $b4{l_vnn}||0, template => 'int' },
{ name => 'anime', required => 0, default => '' },
{ name => 'img_nsfw', required => 0, default => 0 },
- { name => 'relations', required => 0, default => '', maxlength => 5000 },
+ { name => 'vnrelations', required => 0, default => '', maxlength => 5000 },
{ name => 'screenshots', required => 0, default => '', maxlength => 1000 },
{ name => 'editsum', maxlength => 5000 },
);
@@ -57,11 +57,11 @@ sub edit {
if(!$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]+),(.+)$/ && (!$vid || $2 != $vid) ? [ $1, $2, $3 ] : () } split /\|\|\|/, $frm->{relations} ];
+ my $relations = [ map { /^([a-z]+),([0-9]+),(.+)$/ && (!$vid || $2 != $vid) ? [ $1, $2, $3 ] : () } split /\|\|\|/, $frm->{vnrelations} ];
my $screenshots = [ map /^[0-9]+,[01],[0-9]+$/ ? [split /,/] : (), split / +/, $frm->{screenshots} ];
$frm->{anime} = join ' ', sort { $a <=> $b } keys %$anime;
- $frm->{relations} = join '|||', map $_->[0].','.$_->[1].','.$_->[2], sort { $a->[1] <=> $b->[1]} @{$relations};
+ $frm->{vnrelations} = join '|||', map $_->[0].','.$_->[1].','.$_->[2], 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;
@@ -83,7 +83,7 @@ sub edit {
($nvid, $cid) = $self->dbVNAdd(%args) if !$vid;
# update reverse relations & relation graph
- if(!$vid && $#$relations >= 0 || $vid && $frm->{relations} ne $b4{relations}) {
+ if(!$vid && $#$relations >= 0 || $vid && $frm->{vnrelations} ne $b4{vnrelations}) {
my %old = $vid ? (map { $_->{id} => $_->{relation} } @{$v->{relations}}) : ();
my %new = map { $_->[1] => $_->[0] } @$relations;
_updreverse($self, \%old, \%new, $nvid, $cid, $nrev);
@@ -183,7 +183,7 @@ sub _form {
],
vn_rel => [ mt('_vnedit_rel'),
- [ hidden => short => 'relations' ],
+ [ hidden => short => 'vnrelations' ],
[ static => nolabel => 1, content => sub {
h2 mt '_vnedit_rel_sel';
table;
@@ -196,10 +196,10 @@ sub _form {
# TODO: localize JS relartion selector
table;
Tr id => 'relation_new';
- td class => 'tc1';
+ td class => 'tc_vn';
input type => 'text', class => 'text';
end;
- td class => 'tc2';
+ td class => 'tc_rel';
txt ' is a ';
Select;
option value => $_, mt "_vnrel_$_"
@@ -207,8 +207,8 @@ sub _form {
end;
txt ' of';
end;
- td class => 'tc3', $v ? $v->{title} : '';
- td class => 'tc4';
+ td class => 'tc_title', $v ? $v->{title} : '';
+ td class => 'tc_add';
a href => '#', 'add';
end;
end;
diff --git a/static/f/forms.js b/static/f/forms.js
index 57513735..cf03ebc4 100644
--- a/static/f/forms.js
+++ b/static/f/forms.js
@@ -1,170 +1,6 @@
function qq(v) {
return v.replace(/&/g,"&amp;").replace(/</,"&lt;").replace(/>/,"&gt;").replace(/"/g,'&quot;');
}
-function shorten(v, l) {
- return qq(v.length > l ? v.substr(0, l-3)+'...' : v);
-}
-
-
-
-
- /*****************************\
- * V N R E L A T I O N S *
- \*****************************/
-
-
-var relTypes = [];
-function relLoad() {
- var i;var l;var o;
-
- // fetch the relation types from the add new relation selectbox
- l = x('relation_new').getElementsByTagName('select')[0].options;
- for(i=0;i<l.length;i++)
- relTypes[l[i].value] = l[i].text;
-
- // read the current relations
- l = x('relations').value.split('|||');
- if(l[0]) {
- for(i=0;i<l.length;i++) {
- var rel = l[i].split(',', 3);
- relAdd(rel[0], rel[1], rel[2]);
- }
- }
- relEmpty();
-
- // make sure the title is up-to-date
- x('title').onchange = function() {
- l = x('jt_box_vn_rel').getElementsByTagName('td');
- for(i=0;i<l.length;i++)
- if(l[i].className == 'tc3')
- l[i].innerHTML = shorten(this.value, 40);
- };
-
- // bind the add-link
- x('relation_new').getElementsByTagName('a')[0].onclick = relFormAdd;
-
- // dropdown
- dsInit(x('relation_new').getElementsByTagName('input')[0], '/xml/vn.xml?q=', function(item, tr) {
- var td = document.createElement('td');
- td.innerHTML = 'v'+item.getAttribute('id');
- td.style.textAlign = 'right';
- td.style.paddingRight = '5px';
- tr.appendChild(td);
- td = document.createElement('td');
- td.innerHTML = shorten(item.firstChild.nodeValue, 40);
- tr.appendChild(td);
- }, function(item) {
- return 'v'+item.getAttribute('id')+':'+item.firstChild.nodeValue;
- }, relFormAdd);
-}
-
-function relAdd(rel, vid, title) {
- var o = document.createElement('tr');
- o.setAttribute('id', 'relation_tr_'+vid);
-
- var t = document.createElement('td');
- t.className = 'tc1';
- t.innerHTML = 'v'+vid+':<a href="/v'+vid+'">'+shorten(title, 40)+'</a>';
- o.appendChild(t);
-
- var options = '';
- for(var i in relTypes)
- options += '<option value="'+i+'"'+(i == rel ? ' selected="selected"' : '')+'>'+qq(relTypes[i])+'</option>';
- t = document.createElement('td');
- t.className = 'tc2';
- t.innerHTML = 'is a <select onchange="relSerialize()">'+options+'</select> of';
- o.appendChild(t);
-
- t = document.createElement('td');
- t.className = 'tc3';
- t.innerHTML = shorten(x('title').value, 40);
- o.appendChild(t);
-
- t = document.createElement('td');
- t.className = 'tc4';
- t.innerHTML = '<a href="#" onclick="return relDel('+vid+')">del</a>';
- o.appendChild(t);
-
- x('relation_tbl').appendChild(o);
- relEmpty();
-}
-
-function relEmpty() {
- if(x('relation_tbl').getElementsByTagName('tr').length > 0) {
- if(x('relation_tr_none'))
- x('relation_tbl').removeChild(x('relation_tr_none'));
- return;
- }
- var o = document.createElement('tr');
- o.setAttribute('id', 'relation_tr_none');
- var t = document.createElement('td');
- t.colspan = 4;
- t.innerHTML = 'No relations selected.';
- o.appendChild(t);
- x('relation_tbl').appendChild(o);
-}
-
-function relSerialize() {
- var r='';
- var i;
- var l = x('relation_tbl').getElementsByTagName('tr');
- for(i=0;i<l.length;i++) {
- var title = l[i].getElementsByTagName('td')[0];
- var rel = l[i].getElementsByTagName('select')[0];
- title = title.innerText || title.textContent;
- title = title.substr(title.indexOf(':')+1);
- r += (r ? '|||' : '')
- +rel.options[rel.selectedIndex].value
- +','+l[i].id.substr(12)+','+title;
- }
- x('relations').value = r;
-}
-
-function relDel(vid) {
- x('relation_tbl').removeChild(x('relation_tr_'+vid));
- relSerialize();
- relEmpty();
- return false;
-}
-
-function relFormAdd() {
- var txt = x('relation_new').getElementsByTagName('input')[0];
- var sel = x('relation_new').getElementsByTagName('select')[0];
- var lnk = x('relation_new').getElementsByTagName('a')[0];
- var input = txt.value;
-
- if(!input.match(/^v[0-9]+/)) {
- alert('Visual novel textbox must start with an ID (e.g. v17)');
- return false;
- }
-
- txt.disabled = true;
- txt.value = 'loading...';
- sel.disabled = true;
- lnk.innerHTML = 'loading...';
-
- ajax('/xml/vn.xml?q='+encodeURIComponent(input), function(hr) {
- txt.disabled = false;
- txt.value = '';
- sel.disabled = false;
- lnk.innerHTML = 'add';
-
- var items = hr.responseXML.getElementsByTagName('item');
- if(items.length < 1)
- return alert('Visual novel not found!');
-
- var id = items[0].getAttribute('id');
- if(x('relation_tr_'+id))
- return alert('This visual novel has already been selected!');
-
- relAdd(sel.selectedIndex, id, items[0].firstChild.nodeValue);
- sel.selectedIndex = 0;
- relSerialize();
- });
- return false;
-}
-
-
@@ -779,8 +615,6 @@ function tglSerialize() {
// load
-if(x('relations'))
- relLoad();
if(x('jt_box_vn_scr'))
scrLoad();
if(x('media'))
diff --git a/static/f/script.js b/static/f/script.js
index 715e6240..47bce2c1 100644
--- a/static/f/script.js
+++ b/static/f/script.js
@@ -139,7 +139,7 @@ function setClass(obj, c, set) {
}
function shorten(v, l) {
- return qq(v.length > l ? v.substr(0, l-3)+'...' : v);
+ return v.length > l ? v.substr(0, l-3)+'...' : v;
}
@@ -221,7 +221,7 @@ function ivView(what) {
// update document
view.style.display = 'block';
- setContent(x('ivimg'), tag('img', {src:u, onclick:ivClose,
+ setContent(byId('ivimg'), tag('img', {src:u, onclick:ivClose,
onload: function() { byId('ivimgload').style.top='-400px'; },
style: 'width: '+w+'px; height: '+h+'px'
}));
@@ -547,8 +547,14 @@ function dsKeyDown(ev) {
obj.value = obj.ds_serFunc(byId('ds_box_'+obj.ds_selectedId).ds_itemData, obj);
if(obj.ds_returnFunc)
obj.ds_returnFunc();
+
byId('ds_box').style.top = '-500px';
+ setContent(byId('ds_box'), tag('b', 'Loading...'));
obj.ds_selectedId = 0;
+ if(obj.ds_dosearch) {
+ clearTimeout(obj.ds_dosearch);
+ obj.ds_dosearch = null;
+ }
return false;
}
@@ -669,6 +675,126 @@ function dsResults(hr, obj) {
+/* V I S U A L N O V E L R E L A T I O N S (/v+/edit) */
+
+function vnrLoad() {
+ // read the current relations
+ var rels = byId('vnrelations').value.split('|||');
+ for(var i=0; i<rels.length; i++) {
+ var rel = rels[i].split(',', 3);
+ vnrAdd(rel[0], rel[1], rel[2]);
+ }
+ 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<l.length; i++)
+ setText(l[i], shorten(this.value, 40));
+ };
+
+ // bind the add-link
+ byName(byClass(byId('relation_new'), 'td', 'tc_add')[0], 'a')[0].onclick = vnrFormAdd;
+
+ // dropdown
+ dsInit(byName(byClass(byId('relation_new'), 'td', 'tc_vn')[0], 'input')[0], '/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;
+ }, vnrFormAdd);
+}
+
+function vnrAdd(rel, vid, title) {
+ var sel = tag('select', {onchange: vnrSerialize});
+ var ops = byName(byClass(byId('relation_new'), 'td', 'tc_rel')[0], 'select')[0].options;
+ for(var i=0; i<ops.length; i++)
+ sel.appendChild(tag('option', {value: ops[i].value, selected: ops[i].value==rel}, getText(ops[i])));
+
+ byId('relation_tbl').appendChild(tag('tr', {id:'relation_tr_'+vid},
+ tag('td', {class:'tc_vn' }, 'v'+vid+':', tag('a', {href:'/v'+vid}, shorten(title, 40))),
+ tag('td', {class:'tc_rel' }, 'is a ', sel, ' of'),
+ tag('td', {class:'tc_title'}, shorten(byId('title').value, 40)),
+ tag('td', {class:'tc_add' }, tag('a', {href:'#', onclick:vnrDel}, 'del'))
+ ));
+
+ vnrEmpty();
+}
+
+function vnrEmpty() {
+ var tbl = byId('relation_tbl');
+ if(byName(tbl, 'tr').length < 1)
+ tbl.appendChild(tag('tr', {id:'relation_tr_none'}, tag('td', {colspan:4}, 'No relations selected.')));
+ else if(byId('relation_tr_none'))
+ tbl.removeChild(byId('relation_tr_none'));
+}
+
+function vnrSerialize() {
+ var r = [];
+ var trs = byName(byId('relation_tbl'), 'tr');
+ for(var i=0; i<trs.length; i++) {
+ var rel = byName(byClass(trs[i], 'td', 'tc_rel')[0], 'select')[0];
+ r[r.length] = [
+ rel.options[rel.selectedIndex].value, // relation
+ trs[i].id.substr(12), // vid
+ getText(byName(byClass(trs[i], 'td', 'tc_vn')[0], 'a')[0]) // title
+ ].join(',');
+ }
+ byId('vnrelations').value = r.join('|||');
+}
+
+function vnrDel() {
+ var tr = this;
+ while(tr.nodeName.toLowerCase() != 'tr')
+ tr = tr.parentNode;
+ byId('relation_tbl').removeChild(tr);
+ vnrSerialize();
+ vnrEmpty();
+ return false;
+}
+
+function vnrFormAdd() {
+ var relnew = byId('relation_new');
+ var txt = byName(byClass(relnew, 'td', 'tc_vn')[0], 'input')[0];
+ var sel = byName(byClass(relnew, 'td', 'tc_rel')[0], 'select')[0];
+ var lnk = byName(byClass(relnew, 'td', 'tc_add')[0], 'a')[0];
+ var input = txt.value;
+
+ if(!input.match(/^v[0-9]+/)) {
+ alert('Visual novel textbox must start with an ID (e.g. v17)');
+ return false;
+ }
+
+ txt.disabled = sel.disabled = true;
+ txt.value = 'loading...';
+ setText(lnk, 'loading...');
+
+ ajax('/xml/vn.xml?q='+encodeURIComponent(input), function(hr) {
+ txt.disabled = sel.disabled = false;
+ txt.value = '';
+ setText(lnk, 'add');
+
+ var items = hr.responseXML.getElementsByTagName('item');
+ if(items.length < 1)
+ return alert('Visual novel not found!');
+
+ var id = items[0].getAttribute('id');
+ if(byId('relation_tr_'+id))
+ return alert('This visual novel has already been selected!');
+
+ vnrAdd(sel.selectedIndex, id, items[0].firstChild.nodeValue);
+ sel.selectedIndex = 0;
+ vnrSerialize();
+ });
+ return false;
+}
+
+if(byId('vnrelations'))
+ vnrLoad();
+
+
+
+
/* M I S C S T U F F */
// search box