diff options
author | Yorhel <git@yorhel.nl> | 2009-10-05 13:03:43 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2009-10-05 13:03:43 +0200 |
commit | ad638b58f65285285adda787b79b9422ca43313b (patch) | |
tree | 653ce4b7f95ce45670596114992a9707eb7f3b8f | |
parent | d703d1dd64ffcf6af82b2747388a1001228ec30f (diff) |
JS: Moved, rewrote and improved VN tag linking
- You can now click the spoiler column to scroll through the options
- Or mouse-over the spoiler column to see a JS dropdown with the options
(no more select box, which introduces several more clicks to do the same)
-rw-r--r-- | data/style.css | 21 | ||||
-rw-r--r-- | lib/VNDB/Handler/Tags.pm | 33 | ||||
-rw-r--r-- | static/f/forms.js | 143 | ||||
-rw-r--r-- | static/f/script.js | 214 |
4 files changed, 219 insertions, 192 deletions
diff --git a/data/style.css b/data/style.css index d09c7060..139551c9 100644 --- a/data/style.css +++ b/data/style.css @@ -974,15 +974,15 @@ div.browse.uposts td.tc1 { /***** VN tagmod *****/ #jt_box_tagmod .formtable table td { padding: 1px 5px } -#tagtable tfoot td { padding-top: 20px!important; } -#tagtable .tc2_1 { border-right: 1px solid $border$; border-left: 1px solid $border$; width: 150px; text-align: center } -#tagtable .tc3_1 { border-left: 1px solid $border$; width: 150px; text-align: center } -#tagtable .tc1 { min-width: 200px; border-right: 1px solid $border$ } -#tagtable .tc2 { padding-left: 30px!important } -#tagtable .tc3 { border-right: 1px solid $border$; padding-right: 30px!important; text-align: right; padding-left: 10px!important } -#tagtable .tc4 { padding-left: 30px!important; } -#tagtable .tc4 i { font-style: normal; font-size: 8px } -#tagtable .tc5 { text-align: right; padding-right: 30px!important; } +table.tgl tfoot td { padding-top: 20px!important; } +table.tgl .tc_you { border-right: 1px solid $border$; border-left: 1px solid $border$; width: 150px; text-align: center } +table.tgl .tc_others { border-left: 1px solid $border$; width: 150px; text-align: center } +table.tgl .tc_tagname { min-width: 200px; border-right: 1px solid $border$ } +table.tgl .tc_myvote { padding-left: 30px!important } +table.tgl .tc_myspoil { border-right: 1px solid $border$; padding-right: 30px!important; text-align: right; padding-left: 10px!important; cursor: pointer } +table.tgl .tc_allvote { padding-left: 30px!important; } +table.tgl .tc_allvote i { font-style: normal; font-size: 8px } +table.tgl .tc_allspoil { text-align: right; padding-right: 30px!important; } .taglvl { display: block; float: left; width: 8px; height: 12px; border: 1px solid $border$; font-size: 1px; color: $maintext$!important } .taglvl0 { width: 15px; border: none!important; font-size: 10px; text-align: center; } div.taglvl0 { font-size: 8px; width: 20px!important } @@ -994,9 +994,6 @@ a.taglvl:hover { border-bottom: 1px solid transparent!important } .taglvlsel.taglvl1 { background-color: #cf0; border-color: #cf0 } .taglvlsel.taglvl2 { background-color: #8f0; border-color: #8f0 } .taglvlsel.taglvl3 { background-color: #0f0; border-color: #0f0 } -#jt_box_tagmod #tagtable .tc3 { padding: 0 } -#tagtable .tc3 select { width: 90px; height: 15px; border: 0; margin: 0; font-size: 11px; background-color: $_blendbg$; text-align: right } -#tagtable .odd .tc3 select { background-color: $secbg$ } diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm index 8484ad96..0f8b780a 100644 --- a/lib/VNDB/Handler/Tags.pm +++ b/lib/VNDB/Handler/Tags.pm @@ -438,43 +438,44 @@ sub vntagmod { $self->htmlForm({ frm => $frm, action => "/v$vid/tagmod", nosubmit => 1 }, tagmod => [ mt('_tagv_frm_title'), [ hidden => short => 'taglinks', value => '' ], [ static => nolabel => 1, content => sub { - table id => 'tagtable'; + table class => 'tgl'; thead; Tr; td ''; - td colspan => 2, class => 'tc2_1', mt '_tagv_col_you'; - td colspan => 2, class => 'tc3_1', mt '_tagv_col_others'; + td colspan => 2, class => 'tc_you', mt '_tagv_col_you'; + td colspan => 2, class => 'tc_others', mt '_tagv_col_others'; end; Tr; - my $i=0; - td class => 'tc'.++$i, mt '_tagv_col_'.$_ for(qw|tag rating spoiler rating spoiler|); + td class => 'tc_tagname', mt '_tagv_col_tag'; + td class => 'tc_myvote', mt '_tagv_col_rating'; + td class => 'tc_myspoil', mt '_tagv_col_spoiler'; + td class => 'tc_allvote', mt '_tagv_col_rating'; + td class => 'tc_allspoil', mt '_tagv_col_spoiler'; end; end; tfoot; Tr; td colspan => 5; input type => 'submit', class => 'submit', value => mt('_tagv_save'), style => 'float: right'; - input type => 'text', class => 'text', name => 'addtag', value => ''; - input type => 'button', class => 'submit', value => mt '_tagv_add'; + input id => 'tagmod_tag', type => 'text', class => 'text', value => ''; + input id => 'tagmod_add', type => 'button', class => 'submit', value => mt '_tagv_add'; br; p; lit mt '_tagv_addmsg'; end; end; end; end; - tbody; + tbody id => 'tagtable'; for my $t (sort { $a->{name} cmp $b->{name} } @$tags) { my $m = (grep $_->{tag} == $t->{id}, @$my)[0] || {}; - Tr; - td class => 'tc1'; - a href => "/g$t->{id}", $t->{name}; - end; - td class => 'tc2', $m->{vote}||0; - td class => 'tc3', defined $m->{spoiler} ? $m->{spoiler} : -1; - td class => 'tc4'; + Tr id => "tgl_$t->{id}"; + td class => 'tc_tagname'; a href => "/g$t->{id}", $t->{name}; end; + td class => 'tc_myvote', $m->{vote}||0; + td class => 'tc_myspoil', defined $m->{spoiler} ? $m->{spoiler} : -1; + td class => 'tc_allvote'; tagscore !$m->{vote} ? $t->{rating} : $t->{cnt} == 1 ? 0 : ($t->{rating}*$t->{cnt} - $m->{vote}) / ($t->{cnt}-1); i ' ('.($t->{cnt} - ($m->{vote} ? 1 : 0)).')'; end; - td class => 'tc5', sprintf '%.2f', $t->{spoiler}; + td class => 'tc_allspoil', sprintf '%.2f', $t->{spoiler}; end; } end; diff --git a/static/f/forms.js b/static/f/forms.js index d490b0d8..99b8bd13 100644 --- a/static/f/forms.js +++ b/static/f/forms.js @@ -114,153 +114,10 @@ function vnpSerialize(type) { - - - - /****************************************************\ - * V I S U A L N O V E L T A G L I N K I N G * - \****************************************************/ - - -function tglLoad() { - var n = x('tagtable').getElementsByTagName('tfoot')[0].getElementsByTagName('input'); - dsInit(n[1], '/xml/tags.xml?q=', function(item, tr) { - var td = document.createElement('td'); - td.innerHTML = shorten(item.firstChild.nodeValue, 40); - if(item.getAttribute('meta') == 'yes') - td.innerHTML += ' <b class="grayedout">meta</b>'; - else if(item.getAttribute('state') == 0) - td.innerHTML += ' <b class="grayedout">awaiting moderation</b>'; - tr.appendChild(td); - }, function(item) { - return item.firstChild.nodeValue; - }, tglAdd); - n[2].onclick = tglAdd; - - tglStripe(); - var l = x('tagtable').getElementsByTagName('tbody')[0].getElementsByTagName('tr'); - for(var i=0; i<l.length;i++) { - var o = l[i].getElementsByTagName('td'); - tglSpoiler(o[2], parseInt(o[2].innerHTML)); - tglVoteBar(o[1], parseInt(o[1].innerHTML)); - } -} - -function tglSpoiler(obj, spoil) { - var r = '<select onchange="tglSerialize()">'; - for(var i=-1; i<=2; i++) - r += '<option value="'+i+'"'+(spoil==i?' selected="selected"':'')+'>' - +(i == -1 ? 'neutral' : i == 0 ? 'no spoiler' : i == 1 ? 'minor spoiler' : 'major spoiler') - +' </option>'; - obj.innerHTML = r+'</select>'; -} - -function tglVoteBar(obj, vote) { - var r = ''; - for(var i=-3;i<=3;i++) - r += '<a href="#" class="taglvl taglvl'+i+'" onmouseover="tglVoteBarSel(this, '+i+')"' - + ' onmouseout="tglVoteBarSel(this, '+vote+')" onclick="return tglVoteBar(this.parentNode, '+i+')"> </a>'; - obj.innerHTML = r; - tglVoteBarSel(obj, vote); - tglSerialize(); - return false; -} - -function tglVoteBarSel(obj, vote) { - if(obj.className.indexOf('taglvl') >= 0) - obj = obj.parentNode; - var l = obj.getElementsByTagName('a'); - var num; - for(var i=0; i<l.length; i++) { - if((num = l[i].className.replace(/^.*taglvl(-?[0-3]).*$/, "$1")) == l[i].className) - continue; - if(num == 0) - l[i].innerHTML = vote == 0 ? '-' : vote; - else if(num<0&&vote<=num || num>0&&vote>=num) { - if(l[i].className.indexOf('taglvlsel') < 0) - l[i].className += ' taglvlsel'; - } else - if(l[i].className.indexOf('taglvlsel') >= 0) - l[i].className = l[i].className.replace(/taglvlsel/, ''); - } -} - -function tglAdd() { - var n = x('tagtable').getElementsByTagName('tfoot')[0].getElementsByTagName('input'); - n[1].disabled = n[2].disabled = true; - n[2].value = 'loading...'; - ajax('/xml/tags.xml?q=name:'+encodeURIComponent(n[1].value), function(hr) { - n[1].disabled = n[1].disabled = false; - n[2].value = 'Add tag'; - n[1].value = ''; - - var items = hr.responseXML.getElementsByTagName('item'); - if(items.length < 1) - return alert('Item not found!'); - if(items[0].getAttribute('meta') == 'yes') - return alert('Can\'t use meta tags here!'); - var name = items[0].firstChild.nodeValue; - var l = x('tagtable').getElementsByTagName('a'); - for(var i=0; i<l.length; i++) - if(l[i].innerHTML == qq(name)) - return alert('Tag is already present!'); - - var tr = document.createElement('tr'); - var td = document.createElement('td'); - td.innerHTML = '<a href="/g'+items[0].getAttribute('id')+'">'+qq(name)+'</a>'; - td.className = 'tc1'; - tr.appendChild(td); - td = document.createElement('td'); - tglVoteBar(td, 2); - td.className = 'tc2'; - tr.appendChild(td); - td = document.createElement('td'); - tglSpoiler(td, -1); - td.className = 'tc3'; - tr.appendChild(td); - td = document.createElement('td'); - td.className = 'tc4'; - td.innerHTML = '-'; - tr.appendChild(td); - td = document.createElement('td'); - td.innerHTML = '-'; - td.className = 'tc5'; - tr.appendChild(td); - x('tagtable').getElementsByTagName('tbody')[0].appendChild(tr); - tglStripe(); - tglSerialize(); - }); -} - -function tglStripe() { - var l = x('tagtable').getElementsByTagName('tbody')[0].getElementsByTagName('tr'); - for(var i=0;i<l.length;i++) - l[i].className = i%2 ? 'odd' : ''; -} - -function tglSerialize() { - var r = ''; - var l = x('tagtable').getElementsByTagName('tbody')[0].getElementsByTagName('tr'); - for(var i=0; i<l.length;i++) { - var lnk = l[i].getElementsByTagName('a')[0].href; - var vt = l[i].getElementsByTagName('td')[1].getElementsByTagName('a'); - var id; - if((id = lnk.replace(/^.*g([1-9][0-9]*)$/, "$1")) != lnk && vt.length > 3 && vt[3].innerHTML != '-') - r += (r?' ':'')+id+','+vt[3].innerHTML+','+(l[i].getElementsByTagName('select')[0].selectedIndex-1); - } - x('taglinks').value = r; -} - - - - // load if(x('jt_box_rel_vn')) vnpLoad('vn'); if(x('jt_box_rel_prod')) vnpLoad('producers'); -if(x('taglinks')) - tglLoad(); - diff --git a/static/f/script.js b/static/f/script.js index a6c5499c..de0b612d 100644 --- a/static/f/script.js +++ b/static/f/script.js @@ -251,9 +251,10 @@ ivInit(); /* D R O P D O W N */ function ddInit(obj, align, contents) { - obj.dd_align = align; // only 'left' and 'bottom' supported at the moment + 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', dd_used: false})); } @@ -263,6 +264,7 @@ function ddHide() { setText(box, ''); box.style.left = '-500px'; box.dd_used = false; + box.dd_lnk = null; } function ddMouseMove(e) { @@ -278,34 +280,44 @@ function ddMouseMove(e) { 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.id == box.dd_id)) + || (lnk && lnk == box.dd_lnk)) ddHide(); } if(!box.dd_used && lnk) { - var content = lnk.dd_contents(lnk, box); - if(content == null) - return; - setContent(box, content); - box.dd_id = lnk.id; + box.dd_lnk = lnk; box.dd_used = true; - - 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 == 'bottom') - ddy += lnk.offsetHeight; - box.style.left = ddx+'px'; - box.style.top = ddy+'px'; + 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); + + 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; + box.style.left = ddx+'px'; + box.style.top = ddy+'px'; + return true; +} + // release list dropdown on VN pages @@ -1122,6 +1134,166 @@ if(x('jt_box_vn_scr')) +/* V I S U A L N O V E L T A G L I N K I N G (/v+/tagmod) */ + +var tglSpoilers = [ 'neutral', 'no spoiler', 'minor spoiler', 'major spoiler' ]; + +function tglLoad() { + // tag dropdown search + dsInit(byId('tagmod_tag'), '/xml/tags.xml?q=', function(item, tr) { + tr.appendChild(tag('td', + shorten(item.firstChild.nodeValue, 40), + item.getAttribute('meta') == 'yes' ? tag('b', {class:'grayedout'}, ' meta') : + item.getAttribute('state') == 0 ? tag('b', {class:'grayedout'}, ' awaiting moderation') : null + )); + }, function(item) { + return item.firstChild.nodeValue; + }, tglAdd); + byId('tagmod_add').onclick = tglAdd; + + // JS'ify the voting bar and spoiler setting + tglStripe(); + var trs = byName(byId('tagtable'), 'tr'); + for(var i=0; i<trs.length; i++) { + var vote = byClass(trs[i], 'td', 'tc_myvote')[0]; + vote.tgl_vote = getText(vote)*1; + tglVoteBar(vote); + + var spoil = byClass(trs[i], 'td', 'tc_myspoil')[0]; + spoil.tgl_spoil = getText(spoil)*1+1; + setText(spoil, tglSpoilers[spoil.tgl_spoil]); + ddInit(spoil, 'tagmod', tglSpoilDD); + spoil.onclick = tglSpoilNext; + } + tglSerialize(); +} + +function tglSpoilNext() { + if(++this.tgl_spoil >= 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; i<tglSpoilers.length; i++) + lst.appendChild(tag('li', i == lnk.tgl_spoil + ? tag('i', tglSpoilers[i]) + : tag('a', {href: '#', onclick:tglSpoilSet, tgl_td:lnk, tgl_sp:i}, tglSpoilers[i]) + )); + return lst; +} + +function tglSpoilSet() { + this.tgl_td.tgl_spoil = this.tgl_sp; + setText(this.tgl_td, tglSpoilers[this.tgl_sp]); + ddHide(); + tglSerialize(); + return false; +} + +function tglVoteBar(td, vote) { + setText(td, ''); + for(var i=-3; i<=3; i++) + td.appendChild(tag('a', { + class:'taglvl taglvl'+i, tgl_num: i, + onmouseover:tglVoteBarSel, onmouseout:tglVoteBarSel, onclick:tglVoteBarSel + }, ' ')); + tglVoteBarSel(td, td.tgl_vote); + return false; +} + +function tglVoteBarSel(td, vote) { + // nasty trick to make this function multifunctional + if(this && this.tgl_num != null) { + var e = td || window.event; + td = this.parentNode; + vote = this.tgl_num; + if(e.type.toLowerCase() == 'click') { + td.tgl_vote = vote; + tglSerialize(); + } + if(e.type.toLowerCase() == 'mouseout') + vote = td.tgl_vote; + } + var l = byName(td, 'a'); + var num; + for(var i=0; i<l.length; i++) { + num = l[i].tgl_num; + if(num == 0) + setText(l[i], vote || '-'); + else + setClass(l[i], 'taglvlsel', num<0&&vote<=num || num>0&&vote>=num); + } +} + +function tglAdd() { + var tg = byId('tagmod_tag'); + var add = byId('tagmod_add'); + tag.disabled = add.disabled = true; + add.value = 'loading...'; + + ajax('/xml/tags.xml?q=name:'+encodeURIComponent(tg.value), function(hr) { + tg.disabled = add.disabled = false; + tg.value = ''; + add.value = 'Add tag'; + + var items = hr.responseXML.getElementsByTagName('item'); + if(items.length < 1) + return alert('Item not found!'); + if(items[0].getAttribute('meta') == 'yes') + return alert('Can\'t use meta tags here!'); + + var name = items[0].firstChild.nodeValue; + var id = items[0].getAttribute('id'); + if(byId('tgl_'+id)) + return alert('Tag is already present!'); + + 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); + + byId('tagtable').appendChild(tag('tr', {id:'tgl_'+id}, + tag('td', {class:'tc_tagname'}, tag('a', {href:'/g'+id}, name)), + vote, spoil, + tag('td', {class:'tc_allvote'}, '-'), + tag('td', {class:'tc_allspoil'}, '-') + )); + tglStripe(); + tglSerialize(); + }); +} + +function tglStripe() { + var l = byName(byId('tagtable'), 'tr'); + for(var i=0; i<l.length; i++) + setClass(l[i], 'odd', i%2); +} + +function tglSerialize() { + var r = []; + var l = byName(byId('tagtable'), 'tr'); + for(var i=0; i<l.length; i++) { + var vote = byClass(l[i], 'td', 'tc_myvote')[0].tgl_vote; + if(vote != 0) + r[r.length] = [ + l[i].id.substr(4), + vote, + byClass(l[i], 'td', 'tc_myspoil')[0].tgl_spoil-1 + ].join(','); + } + byId('taglinks').value = r.join(' '); +} + +if(byId('taglinks')) + tglLoad(); + + + + /* M I S C S T U F F */ // search box |