// furtka.org logo poll — no cookies, no storage. The server tells us // what this device already chose (salted hash of IP + user agent). (function () { var root = document.querySelector('.poll'); if (!root || !window.fetch) return; var api = root.dataset.api; var status = root.querySelector('.poll-status'); var t = status.dataset; var buttons = root.querySelectorAll('[data-vote]'); var busy = false; function pct(n, total) { return total ? Math.round((n / total) * 100) : 0; } function each(sel, fn) { Array.prototype.forEach.call(root.querySelectorAll(sel), fn); } function render(d) { var total = d.total || 0; root.classList.toggle('poll--voted', !!d.yours); Object.keys(d.counts).forEach(function (k) { var n = d.counts[k], p = pct(n, total), mine = d.yours === k; each('[data-choice="' + k + '"]', function (card) { card.classList.toggle('is-yours', mine); var bar = card.querySelector('.poll-bar i'); if (bar) bar.style.width = p + '%'; var c = card.querySelector('[data-count]'); if (c) c.textContent = d.yours ? p + ' % · ' + n : ''; }); each('[data-vote="' + k + '"]', function (b) { b.disabled = mine; b.textContent = mine ? t.tVoted : (d.yours ? t.tChange : b.dataset.label); }); }); status.textContent = d.yours ? t.tTotal.replace('{n}', total) : ''; } function load() { fetch(api, { headers: { Accept: 'application/json' } }) .then(function (r) { if (!r.ok) throw r; return r.json(); }) .then(render) .catch(function () { status.textContent = t.tError; }); } Array.prototype.forEach.call(buttons, function (b) { b.dataset.label = b.textContent; b.addEventListener('click', function () { if (busy) return; busy = true; b.disabled = true; fetch(api, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body: JSON.stringify({ choice: b.dataset.vote }) }) .then(function (r) { if (!r.ok) throw r; return r.json(); }) .then(function (d) { render(d); status.scrollIntoView({ block: 'nearest' }); }) .catch(function () { status.textContent = t.tError; b.disabled = false; }) .then(function () { busy = false; }); }); }); status.textContent = ''; load(); })();