commit 3c66bb7323452af65dd43e256e03ed0f7444cdac
parent ee0512070d2c443e17da9dfbecf2d96949079f0b
Author: Fredrik <moi@knutsen.co>
Date: Wed, 31 Oct 2018 02:18:40 +0000
Merge pull request #9 from Demonstrandum/devel
Finish adding charts, URL encoding issues and better share page.
Diffstat:
5 files changed, 176 insertions(+), 27 deletions(-)
diff --git a/public/poller.js b/public/poller.js
@@ -58,6 +58,9 @@ const total_other = votes => (
const update_votes = () => {
chart_empty(pie);
const votes = get_votes(POLL_CODE);
+ const enough_other = (Object.values(votes).filter(v => !v.primary)).length > 1;
+ if (Object.values(votes).filter(v => v.primary).length === 0)
+ $('.primary').css({display: 'none'});
$('#primary').empty();
$('#primary').append(`
<tr>
@@ -67,6 +70,7 @@ const update_votes = () => {
<th>Cast</th>
</tr>
`);
+ chart_empty(bar);
$('#other').empty();
$('#other').append(`
<tr>
@@ -83,23 +87,36 @@ const update_votes = () => {
<tr>
<td class="vote-name">${name}</td>
<td class="number" >${votes[name].number}</td>
- <td class="precent">${dp(100 * votes[name].number / total_vote(votes))}</td>
- <td class="cast"><button class="caster" name="${name}" onclick="cast_button('${name}')">Vote</button></td>
+ <td class="percent">${dp(100 * votes[name].number / total_vote(votes))}</td>
+ <td class="cast"><button class="caster" name="${name}" onclick="cast_button('${name.replace(/\'/g, '\\\'')}')">Vote</button></td>
</tr>
`);
} else {
+ push_data(bar, name, votes[name].number)
$('#other').append(`
<tr>
<td class="vote-name">${name}</td>
<td class="number" >${votes[name].number}</td>
- <td class="precent">${dp(100 * votes[name].number / total_vote(votes))}</td>
- <td class="cast"><button class="caster" name="${name}" onclick="cast_button('${name}')">Vote</button></td>
+ <td class="percent">${dp(100 * votes[name].number / total_vote(votes))}</td>
+ <td class="cast"><button class="caster" name="${name}" onclick="cast_button('${name.replace(/\'/g, '\\\'')}')">Vote</button></td>
</tr>
`)
}
}
- if (other_allowed)
+ if (other_allowed && enough_other) {
+ $('#bar').show();
push_data(pie, 'Other', Math.round(total_other(votes)));
+ bar.options.scales.xAxes[0].ticks.min = -1 + Math.min(...(
+ Object.values(votes)
+ .filter(v => !v.primary)
+ .map(v => v.number)
+ ));
+ bar.update();
+ }
+ if (!enough_other) {
+ $('#bar').hide()
+ }
+ chart_colors(pie);
pie.update();
};
@@ -120,7 +137,6 @@ $('document').ready(() => {
url: POLL_CODE + '/has-voted',
async: false,
success: data => {
- console.info('Has already voted?: ', data);
if (data === "true") disable_vote();
}
});
diff --git a/server.rb b/server.rb
@@ -22,11 +22,12 @@ end
def make_poll code, name, alt
alt = alt.to_s == 'true'
poll = {
- :code => code,
- :name => name,
- :votes => {},
- :alt => alt,
- :voters => []
+ :code => code,
+ :name => name,
+ :votes => {},
+ :alt => alt,
+ :voters => [],
+ :created => Time.now
}
POLLS.insert_one poll
end
@@ -72,6 +73,7 @@ get '/share/:code' do
end
post '/new' do
+ params[:code] = URI.decode params[:code]
return nil if poll_exist? params[:code]
make_poll(
@@ -84,7 +86,8 @@ post '/new' do
:"$set" => {
:"votes.#{option}" => {
:number => 0,
- :primary => true
+ :primary => true,
+ :date => Time.now
}
}
})
@@ -107,12 +110,13 @@ post '/poll/:poll/cast' do
return nil if request.ip != '::1' && POLLS.find(:"$and" => [{:code => params[:poll]}, {:voters => request.ip}]).to_a.size > 0
POLLS.update_one({:code => params[:poll]}, {:"$push" => {:voters => request.ip}}) unless request.ip == '::1'
- if POLLS.find({ :"votes.#{params[:vote]}" => {"$exists": true} })
+ if POLLS.find({ :"votes.#{params[:vote]}" => {"$exists": true} }).to_a.size > 0
POLLS.update_one({:code => params[:poll]}, { :"$inc" => { :"votes.#{params[:vote]}.number" => 1 } })
else
- POLLS.update_one({:code => params[:poll]}, { :"$set" => { :"vote.#{params[:vote]}" => {
+ POLLS.update_one({:code => params[:poll]}, { :"$set" => { :"votes.#{params[:vote]}" => {
:number => 1,
- :primary => false
+ :primary => false,
+ :date => Time.now
}}})
end
end
diff --git a/views/index.erb b/views/index.erb
@@ -180,7 +180,7 @@
</script>
<script>
$("#title").on('input', () => {
- $("#code").val(encodeURIComponent($("#title").val().toLowerCase().replace(/\s|\//g, '-')));
+ $("#code").val(encodeURIComponent($("#title").val().toLowerCase().replace(/\s|\\|\//g, '-')));
});
$('#code')[0].addEventListener('keyup', e => {
diff --git a/views/poll.erb b/views/poll.erb
@@ -108,7 +108,7 @@
<div class="container">
<h1><%= name %></h1>
- <div class="row">
+ <div class="row primary">
<div class="seven columns">
<table id="primary" class="live"></table>
</div>
@@ -162,7 +162,6 @@
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
- chart_colors(chart);
}
$(document).ready(() => {
@@ -175,23 +174,59 @@
});
</script>
<script type="text/javascript">
- // PIE CHART:
+ // CHARTS:
let pie;
+ let bar; // Make sure they're global.
$(document).ready(() => {
- const context = $('#pie');
+ const pie_context = $('#pie');
- pie = new Chart(context, {
+ pie = new Chart(pie_context[0], {
type: 'pie',
data: {
labels: [],
datasets: [{
- label: '# of Votes',
+ label: '№ of Votes',
data: [],
backgroundColor: [],
}]
},
- options: {
+ options: {}
+ });
+ const bar_context = $('#bar')
+ bar = new Chart(bar_context[0], {
+ type: 'horizontalBar',
+ data: {
+ labels: [],
+ datasets: [{
+ label: '№ of Votes',
+ data: [],
+ backgroundColor: [],
+ }]
+ },
+ options: {
+ title: {
+ display: true,
+ text: 'Distribution of alternative/other votes.'
+ },
+ scales: {
+ yAxes: [{
+ categoryPercentage: 0.9,
+ barPercentage: 1.0,
+ ticks: {
+ mirror: true,
+ padding: -10,
+ }
+ }],
+ xAxes: [{
+ ticks: {
+ stepSize: 1
+ }
+ }]
+ },
+ legend: {
+ display: false,
+ }
}
});
});
diff --git a/views/share.erb b/views/share.erb
@@ -3,18 +3,112 @@
<head>
<title>Share Poll</title>
<%= head_tags %>
+ <style media="screen">
+ body {
+ overflow: hidden;
+ width: 100vw;
+ height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ h3 {
+ margin: 10px 0;
+ }
+ p {
+ margin: 10px 0;
+ }
+ a, i {
+ padding: 5px 10px;
+ filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.1));
+ border: 1px solid #eee;
+ border-radius: 4px;
+ background: #fff;
+ color: #777;
+ transition: all .1s ease;
+ }
+ a:hover {
+ color: #444;
+ }
+
+ i {
+ cursor: grab;
+ color: #aaa;
+ padding: 0.43em 10px;
+ margin-left: 6px;
+ position: relative;
+ display: inline-block;
+ }
+ i:hover {
+ color: #666;
+ }
+
+ i span {
+ visibility: hidden;
+ width: 120px;
+ background: rgba(0,0,0,0.8);
+ color: #fff;
+ text-align: center;
+ padding: 5px 0;
+ border-radius: 6px;
+
+ position: absolute;
+ z-index: 1;
+ width: 120px;
+ bottom: 100%;
+ left: 50%;
+ margin-left: -60px;
+ font-family: Rubik;
+ font-size: 0.7em;
+ }
+
+ i:hover span {
+ visibility: visible;
+ }
+
+ i span::after {
+ content: " ";
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px;
+ border-style: solid;
+ border-color: rgba(0,0,0,0.8) transparent transparent transparent;
+ }
+ i:active {
+ cursor: copy;
+ }
+ input {
+ position: absolute;
+ right: -300vw;
+ }
+ </style>
</head>
<body>
<div>
- <p>Share:
- <a id="share" href="/poll/<%= params[:code] %>"></a>
- </p>
+ <h3>Share</h3>
+ <p>Share the link with others, press the copy-paste button.</p>
+ <a id="share" href=""><%= params[:code] %></a>
+ <i class="far fa-copy"><span>Copy to Clipboard.</span></i>
+ <input type="text" value="" />
</div>
<script src="/main.js"></script>
<script>
- $("#share").append(`${window.location.protocol}//${window.location.host}/poll/<%= params[:code] %>`)
+ $('i').click(() => {
+ const text = $('#share').text();
+ $('input').val(text);
+ $('input')[0].select();
+ document.execCommand("copy");
+ $('i span').text('Copied!');
+ setTimeout(() => $('i span').text('Copy to Clipboard.'), 700);
+ });
+ const code = $('#share').text();
+ $("#share")
+ .attr('href', `/poll/${encodeURIComponent(code)}`)
+ .text(`${window.location.protocol}//${window.location.host}/poll/${encodeURIComponent(code)}`)
</script>
</body>
</html>