MediaWiki:Gadget-ondemand-arbcomVoting.js: различия между версиями
Перейти к навигации
Перейти к поиску
Содержимое удалено Содержимое добавлено
Kalan (обсуждение | вклад) свежие |
Kalan (обсуждение | вклад) открываем основное голосование |
||
Строка 1: | Строка 1: | ||
(function(){ |
(function(){ |
||
appendCSS('.cand-list { width: 25em } #voting-container ul { margin: 1.5em 0 } #voting-container ul li { width: 19em !important } #voting-help-final { margin: 3em 0 0; border-top: 1px solid #888} .cand-selected { background: #97B6E2 !important } #voting-limited-count { float: right; font-size: 300%; text-align: right; width: 1.5em; line-height: 100%; color: #ff5555 } #voting-limited-count.ok { color: #71C837; font-weight: bold |
appendCSS('.cand-list { width: 25em } #voting-container ul { margin: 1.5em 0 } #voting-container ul li { width: 19em !important } #voting-help-final { margin: 3em 0 0; border-top: 1px solid #888} .cand-selected { background: #97B6E2 !important } #voting-limited-count { float: right; font-size: 300%; text-align: right; width: 1.5em; line-height: 100%; color: #ff5555 } #voting-limited-count.ok { color: #71C837; font-weight: bold }') |
||
function en(e) { return encodeURIComponent(e) } |
function en(e) { return encodeURIComponent(e) } |
||
Строка 39: | Строка 39: | ||
'votinghelp': '<div class="voting-help"><h4>Основная часть</h4>\ |
'votinghelp': '<div class="voting-help"><h4>Основная часть</h4>\ |
||
<p>Голосование завершено, изменения в этой части больше не принимаются.</p>\ |
<p>Голосование завершено, изменения в этой части больше не принимаются.</p>\ |
||
<p |
<p>Расставьте голоса «за» и «против» рядом с именами тех кандидатов, относительно которых у вас сформировано мнение. Вы сможете дополнить или изменить выбор позже.</p>\ |
||
</div>', |
</div>', |
||
'etchelp1': '<div class="voting-help"><h4>Дополнительная часть</h4>\ |
'etchelp1': '<div class="voting-help"><h4>Дополнительная часть</h4>\ |
Версия от 21:43, 22 мая 2012
(function(){
appendCSS('.cand-list { width: 25em } #voting-container ul { margin: 1.5em 0 } #voting-container ul li { width: 19em !important } #voting-help-final { margin: 3em 0 0; border-top: 1px solid #888} .cand-selected { background: #97B6E2 !important } #voting-limited-count { float: right; font-size: 300%; text-align: right; width: 1.5em; line-height: 100%; color: #ff5555 } #voting-limited-count.ok { color: #71C837; font-weight: bold }')
function en(e) { return encodeURIComponent(e) }
function el(e) { return document.createElement(e) }
function tstamp(t) { return !t.getUTCFullYear() ? null : // Safari + Chrome
(t.getUTCFullYear()+":0"+(t.getUTCMonth()+1)+":0"+t.getUTCDate()+":0"+
t.getUTCHours() +":0"+ t.getUTCMinutes() +":0"+t.getUTCSeconds())
.replace(/:0?(\d\d)/g, '$1') }
function ch(o) { for (var i in o) { return o[i] } }
var conf = {
'criteria': {
'count': 500,
'registration': '2012-02-05T23:59:60Z'
},
'pagepath': 'Википедия:Выборы арбитров/Весна 2012/Голосование',
'talkpath': 'Википедия:Выборы арбитров/Весна 2012/Обсуждение/',
'votepath': 'Википедия:Выборы арбитров/Весна 2012/Голосование/',
'start': new Date('May 23 2012 00:00 +0000'),
'end': new Date('May 30 2012 00:00 +0000')
}
var ico = {
'up': '/upwiki/wikipedia/commons/thumb/',
'supp' : '2/2d/Support-gray.svg/39px-Support-gray.svg.png',
'suppinact' : '8/8d/Support-colored.svg/39px-Support-colored.svg.png',
'suppact' : '5/5b/Support-filled.svg/39px-Support-filled.svg.png',
'opp' : 'e/e7/Oppose-gray.svg/39px-Oppose-gray.svg.png',
'oppinact' : '0/06/Oppose-colored.svg/39px-Oppose-colored.svg.png',
'oppact' : '7/7d/Oppose-filled.svg/39px-Oppose-filled.svg.png'
}
var loc = {
'votebutton': 'Проголосовать',
'statuscriteria': 'Проверка критериев…',
'criteriafail': '<h3 class="voting-error">Вы не соответствуете критериям.</h3><p>Ваши голоса на этих выборах <b>не будут засчитаны</b>.</p><p>Впрочем, если вам просто любопытно, как работает скрипт, вы можете посмотреть на него без сохранения голосов.</p>',
'criteriafailbutton': 'Посмотреть',
'loadingvotes': 'Проверка имеющихся голосов…',
'draghere': 'Перетащите первого кандидата сюда',
'votinghelp': '<div class="voting-help"><h4>Основная часть</h4>\
<p>Голосование завершено, изменения в этой части больше не принимаются.</p>\
<p>Расставьте голоса «за» и «против» рядом с именами тех кандидатов, относительно которых у вас сформировано мнение. Вы сможете дополнить или изменить выбор позже.</p>\
</div>',
'etchelp1': '<div class="voting-help"><h4>Дополнительная часть</h4>\
<p>В этот раз дополнительная часть состоит из нескольких опросников. Вы можете принять участие не во всех или вовсе проигнорировать этот блок, но лучше всего заполните все три. Это поможет улучшить процедуру выборов.</p></div>\
<div class="voting-help"><h5>Метод Шульце</h5>\
<ol>\
<li>Перетащите какого-нибудь подходящего, на ваш взгляд, кандидата на первый уровень.</li>\
<li>Перетаскивайте остальных кандидатов в этом же направлении. Кандидатов можно оставлять на существующих уровнях (отмечены цифрами) или на новых (места для их создания обозначены пунктиром). Во время перетаскивания пунктир показывает относительное расположение кандидата в списке.</li>\
<li>Перед сохранением убедитесь в соответствии расстановки вашему мнению: более хорошие кандидаты выше, менее хорошие ниже, равные на одном уровне, совсем неподходящие в разделе «нет предпочтения». Если вы являетесь одним из кандидатов, <em>не оставляйте</em> себя в нижней секции.</li>\
</ol>\
</div>',
'etchelp2': '<div id="voting-etc-schulze"></div>\
<div class="voting-help"><h5>Целевой набор резервных арбитров</h5>\
<p>Оцените, насколько каждый кандидат пригоден на роль <strong>именно резервного арбитра</strong>. Если, по вашему мнению, кандидат будет хорош только как основной арбитр, <strong>не голосуйте за</strong>.</p>\
</div>',
'etchelp3': '<div class="voting-help"><h5>Идеальный состав</h5>\
<p>Выберите <strong>ровно пять</strong> арбитров из списка. Голос за большее или меньшее количество арбитров будет сохранён, но проигнорирован при подсчёте.</p>\
</div>',
'etchelp4': '<div class="voting-help" id="voting-help-final"><p>До конца выборов вы сможете изменить своё мнение.</p>\
<p>Если что-то осталось непонятным, можно <a target="_blank" href="/wiki/Обсуждение_Википедии:Выборы_арбитров/Весна_2012/Голосование">задать вопрос</a>.</p></div>',
'nopreference': 'нет предпочтения',
'newlevel': 'новый уровень',
'justbeforesave': 'Смело направляйте любые отзывы, предложения и сообщения об ошибках на <a href="/wiki/MediaWiki_talk:Script/Voting.js">страницу обсуждения</a>.',
'savebutton': 'Сохранить',
'saveprog': '<b>Не закрывайте страницу</b> до завершения сохранения.',
'summary': '\u200Bг\u200Bол\u200Bос\u200B',
'thankyou': '<h3>Спасибо за участие в выборах!</h3><p>Вы сможете изменить ваши голоса до конца голосования.</p><p>Только что отданные голоса можно посмотреть на <a href="/wiki/Special:Mycontributions">странице вклада</a>.</p>'
}
var cand = 'Biathlon ! Cemenarist ! DR ! Generous ! Michgrig ! Mstislavl ! RussianSpy ! VasilievVV ! Vladimir Solovjev ! Vlsergey ! Wanderer ! Дядя Фред ! Рулин'.split(' ! ')
var wgAPIPath = wgServer + wgScriptPath + '/api.php?format=json&'
var votes = {}
var criteriaMatch
var saving = null
var aj = sajax_init_object()
var aj2 = sajax_init_object()
var token
// drag-n-drop
var coo
var cooD
var drag, dragGhost, dragItem, dragOriginal
var dragHere
function votingStart() {
importStylesheetURI('//ru.wikipedia.org/ruwiki/w/index.php?title=MediaWiki:Voting7.css&action=raw&ctype=text/css')
btn.disabled = true
btn.style.display = 'none'
status.innerHTML = loc.statuscriteria
aj2.onreadystatechange = votingStartContinue
aj2.open('GET', wgAPIPath + 'action=query&list=users&usprop=registration|editcount&prop=revisions&rvprop=content&ususers=' +
en(wgUserName) + '&titles=' + en(conf.votepath + '^'), true)
aj2.send('')
}
function votingStartContinue() {
if (aj2.readyState != 4) return
if (aj2.status != 200) { // temporary problems?
votingStart()
return
}
query = eval('(' + aj2.responseText + ')').query
userinfo = query.users[0]
if ((// a valid voter must be a non-anonymous user
userinfo.missing !== undefined ||
// who is not blocked
userinfo.blockedby ||
// whose editcount is at least conf.criteria.count
userinfo.editcount < conf.criteria.count ||
// and who is registered no later than conf.criteria.registration
// "null" means "before 2005-12-29", user creation was not logged before then
(userinfo.registration !== null && userinfo.registration > conf.criteria.registration)) &&
// exemptions
('\n' + ch(query.pages).revisions[0]['*'] + '\n').indexOf('\n* %\n'.replace('%', wgUserName)) == -1)
votingCriteriaFail()
else {
criteriaMatch = 1
votingContinue()
}
}
function votingCriteriaFail() {
status.innerHTML = loc.criteriafail
btn.style.display = ''
btn.disabled = false
btn.value = loc.criteriafailbutton
btn.onclick = function(){criteriaMatch = 0; votingContinue()}
}
function votingContinue() {
status.innerHTML = loc.loadingvotes
btn.style.display = ''
btn.onclick = votingToken
btn.value = loc.savebutton
btn.disabled = true
// latest contributions in ns:4 + Schulze method page
aj.open('GET', wgAPIPath + 'action=query' +
'&list=usercontribs&ucnamespace=4&uclimit=500' +
'&ucuser=' + en(wgUserName) +
(tstamp(conf.start) ? '&ucend=' + tstamp(conf.start) : '') +
'&ucdir=older' +
'&fake=1&prop=revisions&rvprop=content' +
'&titles=' + en(conf.votepath+'$|')
+ en(conf.votepath+'%|')
+ en(conf.votepath+'=') ,
true)
aj.onreadystatechange = votingDraw
aj.send('')
}
function votingDraw() {
if (aj.readyState != 4) return
if (aj.status != 200) { // temporary problems?
votingContinue()
return
}
btn.disabled = !criteriaMatch
status.innerHTML = ''
var query = eval('(' + aj.responseText + ')')
query = query.query
var co = query.usercontribs
for (var k in query.pages) {
spl = query.pages[k].revisions[0]['*'].split('\n')
switch (query.pages[k].title.match(/(.)$/)[1]) {
case '$':
var sc = spl
break
case '%':
var reserve = spl
break
case '=':
var limited = spl
break
}
}
// retrieving "traditional" votes, according to contributions, only latest ones are valid
for (i=0; i<cand.length; i++) votes[cand[i]] = {'orig':0, 'value':0}
for (var i=co.length-1; i>=0; i--) {
var m = co[i].title.indexOf(conf.votepath) == 0
if (m) m = co[i].title.match(/\/([+-])\/(.*?)$/)
if (m) votes[m[2]] = { 'orig' : m[1]=='+' ? +1 : -1,
'value': 0 }
}
// retrieving Schulze method page
// we assume that the bot will immediately revert not-well-formed edits
for (i=0; i<sc.length; i++) {
if (sc[i].indexOf('* ' + wgUserName + ' | ') == 0) {
votes._s = {'reading': true}
var j = 0
continue
}
if (!votes._s) continue
if (sc[i].indexOf('* ') == 0) votes._s.reading = undefined
if (votes._s.reading) {
j++
var m = sc[i].match(/^\*(.) (.*)/)
m[2] = m[2].split(' | ')
votes._s[m[1]=='#'?j:0] = m[2]
}
}
if (!votes._s) {
votes._s = {0: cand}
}
if (!votes._s[1]) votes._s[1] = []
if (!votes._s[0]) votes._s[0] = []
if (votes._s.reading) votes._s.reading = undefined
// retrieving "reserve" voting
votes._r = {}
for (i = 0; i < cand.length; ++i)
votes._r[cand[i]] = { 'orig' : 0, 'value': 0 }
reading = false
for (i=0; i<reserve.length; i++) {
if (reserve[i].indexOf('* ' + wgUserName + ' | ') == 0) {
reading = true
continue
}
if (!votes._r) continue
if (reserve[i].indexOf('* ') == 0) reading = false
if (reading) {
m = reserve[i].match(/^\*: (.) (.*)$/)
votes._r[m[2]].orig = votes._r[m[2]].value = ((m[1] == '.') ? 0 : (m[1] == '+' ? 1 : -1))
}
}
// retrieving "limited" voting
votes._l = {}
for (i = 0; i < cand.length; ++i)
votes._l[cand[i]] = { 'orig' : 0, 'value': 0 }
reading = false
for (i=0; i<limited.length; i++) {
if (limited[i].indexOf('* ' + wgUserName + ' | ') == 0) {
reading = true
continue
}
if (!votes._l) continue
if (limited[i].indexOf('* ') == 0) reading = false
if (reading) {
m = limited[i].match(/^\*: (.) (.*)$/)
votes._l[m[2]].orig = votes._l[m[2]].value = ((m[1] == '.') ? 0 : 1)
}
}
// drawing
var div1 = el('div')
div1.id = 'voting-standard'
div1.innerHTML = loc.votinghelp
var tab = el('table')
var tr, img, td1, td2, td3, lin
for (i in votes) {
if (!i.match(/^_[srl]$/)) {
tr = el('tr')
td1 = el('td')
img = el('img')
img.alt = '+'
img.width = img.height = 39
img.src = ico.up + (votes[i].orig == 1 ? ico.suppinact : ico.supp)
lin = el('a')
lin.href = '#'
lin.title = '+'
lin.appendChild(img)
td1.appendChild(lin)
td2 = el('td')
img = el('img')
img.alt = '−'
img.width = img.height = 39
img.src = ico.up + (votes[i].orig == -1 ? ico.oppinact : ico.opp)
lin = el('a')
lin.href = '#'
lin.title = '-'
lin.appendChild(img)
td2.appendChild(lin)
td3 = el('td')
td3.className = 'talklink'
lin = el('a')
lin.href = wgServer + wgScript + '?title=' + encodeURI(conf.talkpath + i)
lin.target = '_blank'
lin.innerHTML = i
td3.appendChild(lin)
tr.appendChild(td1)
tr.appendChild(td2)
tr.appendChild(td3)
tab.appendChild(tr)
}
}
div1.appendChild(tab)
// IE has problems inserting the table
div1.innerHTML += ''
var imgs = div1.getElementsByTagName('img')
for (i=0; i<imgs.length; i++)
imgs[i].parentNode.onclick = oncl
dragHere = el('span')
dragHere.id = 'voting-draghere'
dragHere.innerHTML = loc.draghere
var divetc = el('div')
divetc.id = 'voting-schulze'
var div2 = el('div')
div2.id = 'voting-etc-schulze'
div2.innerHTML = loc.etchelp1
var ul = el('ul')
ul.id = 'schulze-list'
var gw, theid, can, first, level, spc
var c
for (i=1; i!=null; i==0 ? i=null : i++) {
gw = el('li')
gw.className = 'groundwork'
theid = el('div')
theid.className = 'li-id'
theid.innerHTML = !votes._s[i] ? i : (i==1 ? '' : i-1) + '…' + i
gw.appendChild(theid)
if (!votes._s[i]) i=0
level = el('li')
level.className = 'level'
if (i==0) level.id = 'voting-no-preference'
if (i==1 && votes._s[i].join('!') == '') {
level.appendChild(dragHere)
}
theid = el('div')
theid.className = 'li-id'
theid.innerHTML = i==0 ? loc.nopreference : i
level.appendChild(theid)
for (c=0; c<votes._s[i].length; c++) {
can = el('a')
can.onclick = function() { return false }
can.onmousedown = boxMouseDown
can.innerHTML = votes._s[i][c]
can.className = 'cand'
level.appendChild(can)
}
level.appendChild(spacer())
ul.appendChild(gw)
ul.appendChild(level)
}
div2.appendChild(ul)
divetc.appendChild(div2)
var div2 = el('div')
div2.id = 'voting-etc-reserve'
div2.innerHTML = loc.etchelp2
var tab = el('table')
var tr, img, td1, td2, td3, lin
for (i in votes._r) {
tr = el('tr')
td1 = el('td')
img = el('img')
img.alt = '+'
img.width = img.height = 19
img.src = ico.up + (votes._r[i].orig == 1 ? ico.suppinact : ico.supp)
lin = el('a')
lin.href = '#'
lin.title = '+'
lin.appendChild(img)
td1.appendChild(lin)
td2 = el('td')
img = el('img')
img.alt = '−'
img.width = img.height = 19
img.src = ico.up + (votes._r[i].orig == -1 ? ico.oppinact : ico.opp)
lin = el('a')
lin.href = '#'
lin.title = '-'
lin.appendChild(img)
td2.appendChild(lin)
td3 = el('td')
td3.className = 'talklink'
lin = el('a')
lin.href = wgServer + wgScript + '?title=' + encodeURI(conf.talkpath + i)
lin.target = '_blank'
lin.innerHTML = i
td3.appendChild(lin)
tr.appendChild(td1)
tr.appendChild(td2)
tr.appendChild(td3)
tab.appendChild(tr)
}
div2.appendChild(tab)
var imgs = div2.getElementsByTagName('img')
for (i=0; i<imgs.length; i++) {
imgs[i].src = imgs[i].src.replace(/39px/, '19px')
imgs[i].parentNode.onclick = onclr
}
divetc.appendChild(div2)
var div2 = el('div')
div2.id = 'voting-etc-limited'
div2.innerHTML = loc.etchelp3
var count = 0
var hol = el('div')
hol.className = 'cand-list'
for (i in votes._l) {
one = el('a')
one.innerHTML = i
one.className = votes._l[i].orig ? 'cand cand-selected' : 'cand'
count += votes._l[i].orig
one.href = '#'
one.onclick = oncll
hol.appendChild(one)
}
var cnt = el('div')
cnt.id = 'voting-limited-count'
cnt.innerHTML = count
if (count == 5) cnt.className = 'ok'
div2.appendChild(cnt)
div2.appendChild(hol)
divetc.appendChild(div2)
var div2 = el('div')
div2.innerHTML = loc.etchelp4
divetc.appendChild(div2)
if (navigator.appName=='Microsoft Internet Explorer') {
// troubles with scopes
document.onmousemove = mouseMove
document.onmouseup = mouseUp
} else {
hookEvent('mousemove', mouseMove)
hookEvent('mouseup', mouseUp)
}
status.innerHTML = loc.justbeforesave
status.parentNode.insertBefore(div1, status)
status.parentNode.insertBefore(divetc, status)
}
function votingToken() {
aj = sajax_init_object()
aj.onreadystatechange = votingTokenContinue
aj.open('GET', wgAPIPath + 'action=query&prop=info&intoken=edit&titles=42', true)
aj.send('')
}
function votingTokenContinue() {
if (aj.readyState != 4) return
if (aj.readyState == 4 && aj.status != 200) {
votingToken()
return
}
token = eval('(' + aj.responseText + ')')
token = ch(token.query.pages).edittoken
votingSave()
}
function votingSave() {
if (saving == null) {
var div = el('div')
div.id = 'voting-saving'
div.innerHTML = '<div id="voting-progress"><div id="voting-progress-progress" style="width:0%"> </div></div>' + loc.saveprog
status.parentNode.appendChild(div)
btn.disabled = true
document.getElementById('voting-schulze' ).style.visibility = 'hidden'
document.getElementById('voting-standard').style.visibility = 'hidden'
saving = {'cursor': 0, 'pages': []}
for (var i in votes) {
if (votes[i].value != 0 && votes[i].orig != votes[i].value) {
saving.pages[saving.cursor++] = {'text': '\n# [[user:' + wgUserName + '|' + wgUserName + ']] ~' + '~~' + '~~\n',
'page': conf.votepath + (votes[i].value==1?'+':'-') + '/' + i}
}
}
var text, text2, changed
var ms, mi
var li = document.getElementById('schulze-list').getElementsByTagName('li')
text = text2 = '\n* ' + wgUserName + ' | ~' + '~~' + '~~\n'
for (i=0; i<li.length; i++) {
ms = li[i].getElementsByTagName('a')
if (ms.length) {
mi = []
for (var j=0; j<ms.length; j++) mi[mi.length] = ms[j].innerHTML
text += (li[i].id == 'voting-no-preference' ? '*: ' : '*# ') + mi.join(' | ') + '\n'
}
}
for (i=1; i!=null; i==0 ? i=null : i++) {
if (!votes._s[i]) i=0
if (votes._s[i].join('.')) text2 += (i==0 ? '*: ' : '*# ') + votes._s[i].join(' | ') + '\n'
}
if (text != text2) {
saving.pages[saving.cursor++] = {'page': conf.votepath + '$',
'text': text}
}
text = '\n* ' + wgUserName + ' | ~' + '~~' + '~~\n'
changed = false
for (var i in votes._l) {
text += '*: ' + (votes._l[i].value ? '+' : '.') + ' ' + i + '\n'
if (votes._l[i].orig != votes._l[i].value)
changed = true
}
if (changed) {
saving.pages[saving.cursor++] = {'page': conf.votepath + '=',
'text': text}
}
text = '\n* ' + wgUserName + ' | ~' + '~~' + '~~\n'
changed = false
var vd = {99: '-', 100: '.', 101: '+'}
for (var i in votes._r) {
text += '*: ' + vd[votes._r[i].value + 100] + ' ' + i + '\n'
if (votes._l[i].orig != votes._l[i].value)
changed = true
}
if (changed) {
saving.pages[saving.cursor++] = {'page': conf.votepath + '%',
'text': text}
}
saving.cursor = -5
if (saving.pages.length)
votingSave()
else
document.getElementById('voting-container').innerHTML = loc.thankyou
} else {
if (saving.cursor != -5 && aj.readyState != 4) return
if (aj.readyState == 4 && aj.status != 200) {
votingSave()
return
}
if (saving.cursor == -5) saving.cursor = 0
if (saving.cursor == -1) return
document.getElementById('voting-progress-progress').style.width = 100*(saving.cursor+1)/saving.pages.length + '%'
aj = sajax_init_object()
aj.open('POST', wgAPIPath + 'action=edit¬minor=1&unwatch=1&token=' + en(token) + '&summary=' + en(loc.summary) +
'&title=' + en(saving.pages[saving.cursor].page) +
'&appendtext=' + en(saving.pages[saving.cursor].text), true)
aj.onreadystatechange = votingSave
aj.send('')
saving.cursor++
if (!saving.pages[saving.cursor]) {
saving.cursor = -1
document.getElementById('voting-container').innerHTML = loc.thankyou
}
}
}
// onclick() for round buttons
function oncl() {
var imgs = this.parentNode.parentNode.getElementsByTagName('img')
var link = this.parentNode.parentNode.getElementsByTagName('a')[2]
var ca = link.innerHTML
var ti = this.title
var vo = ti=='+'?1:-1
votes[ca].value = (votes[ca].value==vo) ? 0 : vo
imgs[0].src = ico.up + (votes[ca].value== 1 ?ico.suppact:(votes[ca].orig== 1 ?ico.suppinact:ico.supp))
imgs[1].src = ico.up + (votes[ca].value==-1 ?ico.oppact :(votes[ca].orig==-1 ?ico.oppinact :ico.opp))
link.className = ['opp', '', 'supp'][votes[ca].value + 1]
return false
}
function onclr() {
var imgs = this.parentNode.parentNode.getElementsByTagName('img')
var link = this.parentNode.parentNode.getElementsByTagName('a')[2]
var ca = link.innerHTML
var ti = this.title
var vo = ti=='+'?1:-1
votes._r[ca].value = (votes._r[ca].value==vo) ? 0 : vo
imgs[0].src = ico.up + (votes._r[ca].value== 1 ?ico.suppact:(votes._r[ca].orig== 1 ?ico.suppinact:ico.supp)).replace(/39px/, '19px')
imgs[1].src = ico.up + (votes._r[ca].value==-1 ?ico.oppact :(votes._r[ca].orig==-1 ?ico.oppinact :ico.opp)).replace(/39px/, '19px')
link.className = ['opp', '', 'supp'][votes._r[ca].value + 1]
return false
}
function oncll() {
if (this.className == 'cand')
this.className = 'cand cand-selected'
else
this.className = 'cand'
var ca = this.innerHTML
votes._l[ca].value = (this.className == 'cand')?0:1
var count = 0
for (var i in votes._l)
count += votes._l[i].value
document.getElementById('voting-limited-count').innerHTML = count
document.getElementById('voting-limited-count').className = (count==5)?'ok':''
return false
}
// used by drag-n-drop
function disableSelection(el, g){
// doesn't work for Opera, thus onmousemove drops selection ranges
el.onselectstart = g ? function(){ return false } : null
el.unselectable = g ? "on" : "off"
el.style.MozUserSelect = g ? "none" : ""
}
function absolutePosition(el) {
q = el
co = {'x': 0, 'y': 0}
while (q.offsetParent){
co.x += q.offsetLeft
co.y += q.offsetTop
q = q.offsetParent
}
return co
}
function coords(e) {
if (e.pageX !== undefined)
return {'x': e.pageX, 'y': e.pageY}
else // IE (buggy for v7 while zoomed, but who cares?)
return {
'x': e.clientX + document.documentElement.scrollLeft,
'y': e.clientY + document.documentElement.scrollTop
}
}
function boxMouseDown() {
if (dragHere && dragHere.parentNode) dragHere.parentNode.removeChild(dragHere)
dragGhost = this
dragGhost.id = 'voting-ghost'
dragOriginal = dragItem = this.parentNode
dragItem.className += ' dragitem'
drag = document.createElement('a')
drag.innerHTML = this.innerHTML
drag.id = 'voting-drag'
drag.className = 'cand'
cooD = absolutePosition(dragGhost)
cooD.x -= coo.x
cooD.y -= coo.y
mouseMove({'pageX': coo.x, 'pageY': coo.y})
document.body.appendChild(drag)
disableSelection(document.body, true)
disableSelection(drag, true)
}
function mouseMove(e) {
coo = coords(e || window.event)
if (!drag) return
if (document.defaultView) // Opera: removing selection
document.defaultView.getSelection().removeAllRanges()
drag.style.left = (coo.x + cooD.x) + "px"
drag.style.top = (coo.y + cooD.y) + "px"
var lis = document.getElementById('schulze-list').getElementsByTagName('li')
var dragCurrent
for (i=0; i<lis.length; i++) {
pos = absolutePosition(lis[i])
if (pos.x <= coo.x &&
pos.y <= coo.y &&
pos.x + lis[i].offsetWidth > coo.x &&
pos.y + lis[i].offsetHeight > coo.y) {
dragCurrent = lis[i]
}
}
if (!dragCurrent) { // pointer outside the whole list, returning ghost to its original location
dragCurrent = dragOriginal
}
if (dragCurrent != dragItem) { // changing target level
dragItem.className = dragItem.className.replace(' dragitem', '')
d = dragItem.getElementsByTagName('div')[0]
d.innerHTML = d.innerHTML.replace(/^([^:]+).*/, '$1')
dragItem.removeChild(dragGhost)
dragItem = dragCurrent
dragItem.className += ' dragitem'
if (dragItem.className.match(/groundwork/)) {
dragItem.getElementsByTagName('div')[0].innerHTML += ': ' + loc.newlevel
dragItem.appendChild(dragGhost)
}
else { // not an empty level, so inserting dragGhost in an appropriate place
var bef
var ch = dragItem.getElementsByTagName('a')
var spacer = dragItem.getElementsByTagName('span')[0]
if (ch.length == 0) {
bef = spacer
} else {
bef = ch[0]
for (i=0; i<ch.length; i++)
if (ch[i].innerHTML < dragGhost.innerHTML)
bef = ch[i+1] || spacer
}
dragItem.insertBefore(dragGhost, bef)
}
}
}
function spacer() {
var el = document.createElement('span')
el.className = 'spacer'
el.innerHTML = ' '
return el
}
function mouseUp() {
if (!dragGhost || !drag || !dragItem) return
dragItem.className = dragItem.className.replace(' dragitem', '')
dragItem = null
dragGhost.id = ''
dragGhost = null
disableSelection(document.body, false)
disableSelection(drag, false)
document.body.removeChild(drag)
drag = null
// arranging structures
function groundwork() {
var el = document.createElement('li')
el.className = 'groundwork'
el.innerHTML = '<div class="li-id">!</div>'
return el
}
// creating groundworks around any newly created level
var lis = document.getElementById('schulze-list').getElementsByTagName('li')
for (i=0; i<lis.length-1; i++)
if (lis[i].className == 'groundwork' && lis[i].getElementsByTagName('a').length > 0) {
lis[i].className = 'level'
lis[i].appendChild(spacer())
lis[i].parentNode.insertBefore(groundwork(), lis[i].nextSibling)
lis[i].parentNode.insertBefore(groundwork(), lis[i])
}
// destroying empty levels, except when there's only one
var lis = document.getElementById('schulze-list').getElementsByTagName('li')
if (lis.length > 4)
for (i=0; i<lis.length-1; i++)
if (lis[i].className == 'level' && lis[i].getElementsByTagName('a').length == 0)
lis[i].parentNode.removeChild(lis[i])
// blowing up inevitable duplicate groundworks
var lis = document.getElementById('schulze-list').getElementsByTagName('li')
for (i=1; i<lis.length; i++) {
if (lis[i].className == 'groundwork' && lis[i-1].className == 'groundwork')
lis[i].parentNode.removeChild(lis[i])
}
var lis = document.getElementById('schulze-list').getElementsByTagName('li')
// "drag first candidate here" label
if (lis[1].getElementsByTagName('a').length == 0)
lis[1].insertBefore(dragHere, lis[1].getElementsByTagName('span')[0])
// renumbering
var j = 0
for (i=0; i<lis.length-1; i++) {
lis[i].getElementsByTagName('div')[0].innerHTML =
lis[i].className == 'groundwork'
? (j==0 ? '…'+(++j) : (i==lis.length-2 ? ++j : j+'…'+(++j))) : j
}
}
document.getElementById('voting-container').innerHTML = ''
var btn = el('input')
btn.type = 'button'
btn.id = 'voting-button'
btn.value = loc.votebutton
btn.onclick = votingStart
var status = el('div')
status.id = 'voting-status'
document.getElementById('voting-container').appendChild(status)
document.getElementById('voting-container').appendChild(btn)
})()