commit 88286804eaaea2c862cef333a997dbc707ec2c98
parent 30ffddfa72d7e358fa344de7eeda31b56fa459da
Author: Fredrik <moi@knutsen.co>
Date: Tue, 20 Nov 2018 19:14:27 +0000
Merge pull request #23 from Demonstrandum/devel
Seperate code to appropriate files.
Diffstat:
M | public/new.js | | | 143 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | public/poll.css | | | 93 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | public/stats.js | | | 97 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | public/styles.css | | | 37 | +++++++++++++++++++++++++++++++++++++ |
M | views/index.erb | | | 144 | ------------------------------------------------------------------------------- |
M | views/poll.erb | | | 241 | +------------------------------------------------------------------------------ |
6 files changed, 372 insertions(+), 383 deletions(-)
diff --git a/public/new.js b/public/new.js
@@ -66,3 +66,146 @@ $('document').ready(() => {
return false;
});
});
+
+
+let editing = NaN;
+
+const add_list = option => {
+ $('#addition').val('');
+ let adder = $(".option").detach();
+ $("#options")
+ .append(`
+ <li class="option-item">
+ <span class="value">${option}</span>
+ <div class="symbols">
+ <i class="option-edit far fa-edit"></i>
+ <i class="option-remove fas fa-times"></i>
+ </div>
+ </li>
+ `)
+ .append(adder);
+ $('#addition').focus().select();
+};
+
+
+$('#options').on('click', '.option-remove', e => {
+ const li = $(e.target).closest('li');
+ li.slideUp(100, function() { $(this).remove(); });
+ console.warn(li[0], 'Element been removed!');
+});
+
+const save = () => {
+ const inputs = $('#options li').children('input');
+ let values = Array(...$('#options li span')
+ .filter((i, e) => e.style.display !== 'none')
+ .map((i, e) => e.innerHTML));
+ console.log(values);
+
+ let bad_input = null;
+ inputs.each(function() {
+ const value = this.value;
+ if (value.length === 0) {
+ issue(ISSUE.FATAL, `Cannot leave new value empty. Delete it if you don't want it.`);
+ bad_input = $(this);
+ return;
+ }
+ if (values.includes(value)) {
+ issue(ISSUE.FATAL, `Cannot have duplicate (primary) options/choices!`);
+ bad_input = $(this);
+ return;
+ }
+
+ $(this).parent('li').removeClass('dark-option');
+ $(this).siblings('span').show().text(value);
+ $(this).siblings('.symbols').find('.option-edit')
+ .removeClass('fa-save')
+ .addClass('fa-edit');
+ this.remove();
+ });
+
+ if (bad_input !== null) {
+ bad_input.attention();
+ return false;
+ }
+
+ let value = $("#addition").val().trim();
+
+ if (values.includes(value)) {
+ issue(ISSUE.FATAL, `Cannot have duplicate (primary) options/choices!`);
+ $('#addition').attention();
+ return false;
+ }
+
+
+ if (value.length > 0) add_list(value);
+ return true;
+};
+
+$(document).on('click', e => {
+ if (!( $(e.target).hasClass('editor')
+ || $(e.target).hasClass('option-item')
+ || $(e.target).hasClass('fa-save')
+ || $(e.target).hasClass('value')
+ )) {
+ save();
+ editing = NaN;
+ }
+});
+
+const edit_mode = li => {
+ const span = li.find('span');
+ span.hide();
+ li.addClass('dark-option');
+ li.find('.option-edit')
+ .removeClass('fa-edit')
+ .addClass('fa-save');
+ li.prepend(`<input class="editor" type="text" value="${span.text()}" />`);
+ li.find('input').focus().select();
+};
+
+$('#options').on('click', 'li', e => {
+ if (e.target.nodeName === 'INPUT') return;
+ let li = $(e.currentTarget);
+ save();
+
+ if (editing !== li.index()) {
+ editing = li.index();
+ edit_mode(li);
+ } else {
+ editing = NaN;
+ }
+});
+
+$(document).on('keypress', '.editor', key => {
+ if (key.which === 13 || key.which === 10) {
+ key.preventDefault();
+ save();
+ editing = NaN;
+ }
+});
+
+$("#addition").on('keypress', key => {
+ let value = $("#addition").val().trim();
+ if (key.which === 13 || key.which === 10) {
+ if (value.length === 0) {
+ return $('#addition').attention();
+ }
+ key.preventDefault();
+ save();
+ }
+});
+$('.add-option').click(() => {
+ if ($('#addition').val().length === 0) {
+ $('#addition').attention();
+ return;
+ }
+ save();
+});
+
+$("#title").on('input', () => {
+ $("#code").val(encodeURIComponent($("#title").val().toLowerCase().replace(/\s|\\|\//g, '-')));
+});
+
+$('#code')[0].addEventListener('keyup', e => {
+ $("#code").val(encodeURIComponent($("#code").val().replace(/[^A-Za-z\d\-\.\!\']/g, '-')));
+});
diff --git a/public/poll.css b/public/poll.css
@@ -0,0 +1,93 @@
+table {
+ width: 100%;
+ border-collapse:separate;
+ border-spacing: 0 0.5em;
+}
+
+td, th {
+ border: none;
+ padding: 0;
+ vertical-align: middle;
+}
+th:not(:first-child) {
+ width: 4em;
+}
+
+td:not(:first-child), th:not(:first-child) {
+ text-align: center;
+}
+
+td:first-child {
+ padding: 0 0 0 10px !important;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+
+td:last-child {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+
+tr:not(:first-child) {
+ border: none;
+ background: #f5f5f5;
+ margin: 0;
+ padding: 0;
+}
+
+tr td:nth-child(2) {
+ background: #eeeeee; /* Gradient-ish */
+}
+tr td:nth-child(3) {
+ background: #e1e1e1;
+}
+tr td:nth-child(4) {
+ background: #d7d7d7;
+}
+.row {
+ display: block;
+ align-items: center;
+ justify-content: center;
+}
+@media (min-width:550px) {
+ .row {
+ display: flex;
+ }
+}
+.row .columns {
+ height: 100%;
+ overflow: auto;
+}
+
+#vote {
+ width: calc(100% - 11em);
+ float: left;
+}
+#submit {
+ width: 11em;
+ padding: 0;
+ float: right;
+}
+.disabled {
+ user-select: none !important;
+ cursor: default !important;
+}
+.caster {
+ border-color: transparent;
+ padding: 5px 10px;
+ background: #f5f5f5;
+ height: 1.4em;
+ line-height: 0.7em;
+ margin: 0;
+ border-radius: 4px;
+}
+
+.caster:active {
+ background: #aaa;
+}
+
+.chart-area {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/public/stats.js b/public/stats.js
@@ -0,0 +1,97 @@
+Chart.defaults.global.elements.arc.borderColor = '#ddd';
+const ALPHA_RANGE = {
+ min: 0.08,
+ max: 1
+}
+
+const chart_colors = chart => {
+ const range = ALPHA_RANGE;
+ const N = chart.data.datasets[0].data.length;
+ backgrounds = Array(N);
+ for (let mono = range.min; mono <= range.max; mono += range.max / (N + 1))
+ backgrounds[Math.round((mono - range.min) * N / range.max)] = `rgba(0,0,0,${mono})`;
+ chart.data.datasets[0].backgroundColor = backgrounds;
+ return backgrounds;
+};
+
+const chart_empty = chart => {
+ chart.data.labels = [];
+ chart.data.datasets[0].data = [];
+};
+
+const push_data = (chart, label, data) => {
+ chart.data.labels.push(label);
+ chart.data.datasets.forEach((dataset) => {
+ dataset.data.push(data);
+ });
+}
+
+$(document).ready(() => {
+ $('.home').click(() => {
+ window.location.href = '/';
+ })
+ for (const canvas of ['#pie', '#bar']) {
+ const context = $(canvas)[0];
+ const dimension = $(canvas).closest('div').innerWidth() - 22;
+ context.height = dimension;
+ context.width = dimension;
+ }
+});
+
+
+// CHARTS:
+let pie;
+let bar; // Make sure they're global.
+$(document).ready(() => {
+ const pie_context = $('#pie');
+
+ pie = new Chart(pie_context[0], {
+ type: 'pie',
+ data: {
+ labels: [],
+ datasets: [{
+ label: '№ of Votes',
+ data: [],
+ backgroundColor: [],
+ }]
+ },
+ 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/public/styles.css b/public/styles.css
@@ -206,6 +206,43 @@ h3 {
text-align: right;
}
+footer {
+ margin-top: 2em;
+ border-top: 1px solid #eee;
+ display: flex;
+ align-items: center;
+ height: 4em;
+ user-select: none;
+}
+footer .container {
+ padding-top: 0;
+ margin-top: 0;
+}
+footer .row {
+ display: flex;
+ align-items: center;
+ justify-content: unset;
+}
+footer .row .left {
+ margin-right: auto;
+}
+footer span {
+ font-weight: bold;
+ font-size: 2em;
+ vertical-align: middle;
+ margin-right: 1em;
+}
+.home {
+ padding: 10px 20px;
+ cursor: pointer;
+ color: #fff;
+ text-transform: uppercase;
+ font-size: 11px;
+ background: #000;
+ border-radius: 4px;
+ float: right
+}
+
.url {
word-break: break-all;
display: block;
diff --git a/views/index.erb b/views/index.erb
@@ -73,149 +73,5 @@
<script src="/main.js"></script>
<script src="/new.js"></script>
- <script>
- let editing = NaN;
-
- const add_list = option => {
- $('#addition').val('');
- let adder = $(".option").detach();
- $("#options")
- .append(`
- <li class="option-item">
- <span class="value">${option}</span>
- <div class="symbols">
- <i class="option-edit far fa-edit"></i>
- <i class="option-remove fas fa-times"></i>
- </div>
- </li>
- `)
- .append(adder);
- $('#addition').focus().select();
- };
-
-
- $('#options').on('click', '.option-remove', e => {
- const li = $(e.target).closest('li');
- li.slideUp(100, function() { $(this).remove(); });
- console.warn(li[0], 'Element been removed!');
- });
-
- const save = () => {
- const inputs = $('#options li').children('input');
- let values = Array(...$('#options li span')
- .filter((i, e) => e.style.display !== 'none')
- .map((i, e) => e.innerHTML));
- console.log(values);
-
- let bad_input = null;
- inputs.each(function() {
- const value = this.value;
- if (value.length === 0) {
- issue(ISSUE.FATAL, `Cannot leave new value empty. Delete it if you don't want it.`);
- bad_input = $(this);
- return;
- }
- if (values.includes(value)) {
- issue(ISSUE.FATAL, `Cannot have duplicate (primary) options/choices!`);
- bad_input = $(this);
- return;
- }
-
- $(this).parent('li').removeClass('dark-option');
- $(this).siblings('span').show().text(value);
- $(this).siblings('.symbols').find('.option-edit')
- .removeClass('fa-save')
- .addClass('fa-edit');
- this.remove();
- });
-
- if (bad_input !== null) {
- bad_input.attention();
- return false;
- }
-
- let value = $("#addition").val().trim();
-
- if (values.includes(value)) {
- issue(ISSUE.FATAL, `Cannot have duplicate (primary) options/choices!`);
- $('#addition').attention();
- return false;
- }
-
-
- if (value.length > 0) add_list(value);
- return true;
- };
-
- $(document).on('click', e => {
- if (!( $(e.target).hasClass('editor')
- || $(e.target).hasClass('option-item')
- || $(e.target).hasClass('fa-save')
- || $(e.target).hasClass('value')
- )) {
- save();
- editing = NaN;
- }
- });
-
- const edit_mode = li => {
- const span = li.find('span');
- span.hide();
- li.addClass('dark-option');
- li.find('.option-edit')
- .removeClass('fa-edit')
- .addClass('fa-save');
- li.prepend(`<input class="editor" type="text" value="${span.text()}" />`);
- li.find('input').focus().select();
- };
-
- $('#options').on('click', 'li', e => {
- if (e.target.nodeName === 'INPUT') return;
- let li = $(e.currentTarget);
- save();
-
- if (editing !== li.index()) {
- editing = li.index();
- edit_mode(li);
- } else {
- editing = NaN;
- }
- });
-
- $(document).on('keypress', '.editor', key => {
- if (key.which === 13 || key.which === 10) {
- key.preventDefault();
- save();
- editing = NaN;
- }
- });
-
- $("#addition").on('keypress', key => {
- let value = $("#addition").val().trim();
- if (key.which === 13 || key.which === 10) {
- if (value.length === 0) {
- return $('#addition').attention();
- }
- key.preventDefault();
- save();
- }
- });
- $('.add-option').click(() => {
- if ($('#addition').val().length === 0) {
- $('#addition').attention();
- return;
- }
- save();
- });
- </script>
- <script>
- $("#title").on('input', () => {
- $("#code").val(encodeURIComponent($("#title").val().toLowerCase().replace(/\s|\\|\//g, '-')));
- });
-
- $('#code')[0].addEventListener('keyup', e => {
- $("#code").val(encodeURIComponent($("#code").val().replace(/[^A-Za-z\d\-\.\!\']/g, '-')));
- });
- </script>
</body>
</html>
diff --git a/views/poll.erb b/views/poll.erb
@@ -16,107 +16,7 @@
}
</style>
<% end %>
- <style media="screen">
- table {
- width: 100%;
- border-collapse:separate;
- border-spacing: 0 0.5em;
- }
-
- td, th {
- border: none;
- padding: 0;
- vertical-align: middle;
- }
- th:not(:first-child) {
- width: 4em;
- }
-
- td:not(:first-child), th:not(:first-child) {
- text-align: center;
- }
-
- td:first-child {
- padding: 0 0 0 10px !important;
- border-top-left-radius: 4px;
- border-bottom-left-radius: 4px;
- }
-
- td:last-child {
- border-top-right-radius: 4px;
- border-bottom-right-radius: 4px;
- }
-
- tr:not(:first-child) {
- border: none;
- background: #f5f5f5;
- margin: 0;
- padding: 0;
- }
-
- tr td:nth-child(2) {
- background: #eeeeee; /* Gradient-ish */
- }
- tr td:nth-child(3) {
- background: #e1e1e1;
- }
- tr td:nth-child(4) {
- background: #d7d7d7;
- }
- .row {
- display: block;
- align-items: center;
- justify-content: center;
- }
- @media (min-width:550px) {
- .row {
- display: flex;
- }
- }
- .row .columns {
- height: 100%;
- overflow: auto;
- }
-
- #vote {
- width: calc(100% - 11em);
- float: left;
- }
- #submit {
- width: 11em;
- padding: 0;
- float: right;
- }
- .disabled {
- user-select: none !important;
- cursor: default !important;
- }
- .caster {
- border-color: transparent;
- padding: 5px 10px;
- background: #f5f5f5;
- height: 1.4em;
- line-height: 0.7em;
- margin: 0;
- border-radius: 4px;
- }
-
- .caster:active {
- background: #aaa;
- }
-
- .chart-area {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- canvas {
- /*border: 1px solid #f9f9f9;
- background: #fff;
- border-radius: 4px;
- filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.2));*/
- }
- </style>
+ <link rel="stylesheet" type="text/css" href="/poll.css" />
</head>
<body>
<div class="container">
@@ -148,45 +48,6 @@
<br />
</div>
- <style>
- footer {
- margin-top: 2em;
- border-top: 1px solid #eee;
- display: flex;
- align-items: center;
- height: 4em;
- user-select: none;
- }
- footer .container {
- padding-top: 0;
- margin-top: 0;
- }
- footer .row {
- display: flex;
- align-items: center;
- justify-content: unset;
- }
- footer .row .left {
- margin-right: auto;
- }
- footer span {
- font-weight: bold;
- font-size: 2em;
- vertical-align: middle;
- margin-right: 1em;
- }
- .home {
- padding: 10px 20px;
- cursor: pointer;
- color: #fff;
- text-transform: uppercase;
- font-size: 11px;
- background: #000;
- border-radius: 4px;
- float: right
- }
- </style>
-
<footer>
<div class="container">
<div class="row">
@@ -206,105 +67,7 @@
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js" charset="utf-8"></script>
- <script type="text/javascript">
- Chart.defaults.global.elements.arc.borderColor = '#ddd';
- const ALPHA_RANGE = {
- min: 0.08,
- max: 1
- }
-
- const chart_colors = chart => {
- const range = ALPHA_RANGE;
- const N = chart.data.datasets[0].data.length;
- backgrounds = Array(N);
- for (let mono = range.min; mono <= range.max; mono += range.max / (N + 1))
- backgrounds[Math.round((mono - range.min) * N / range.max)] = `rgba(0,0,0,${mono})`;
- chart.data.datasets[0].backgroundColor = backgrounds;
- return backgrounds;
- };
-
- const chart_empty = chart => {
- chart.data.labels = [];
- chart.data.datasets[0].data = [];
- };
-
- const push_data = (chart, label, data) => {
- chart.data.labels.push(label);
- chart.data.datasets.forEach((dataset) => {
- dataset.data.push(data);
- });
- }
-
- $(document).ready(() => {
- $('.home').click(() => {
- window.location.href = '/';
- })
- for (const canvas of ['#pie', '#bar']) {
- const context = $(canvas)[0];
- const dimension = $(canvas).closest('div').innerWidth() - 22;
- context.height = dimension;
- context.width = dimension;
- }
- });
- </script>
- <script type="text/javascript">
- // CHARTS:
- let pie;
- let bar; // Make sure they're global.
- $(document).ready(() => {
- const pie_context = $('#pie');
-
- pie = new Chart(pie_context[0], {
- type: 'pie',
- data: {
- labels: [],
- datasets: [{
- label: '№ of Votes',
- data: [],
- backgroundColor: [],
- }]
- },
- 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,
- }
- }
- });
- });
- </script>
+ <script src="/stats.js"></script>
<script src="/main.js"></script>
<script src="/poller.js"></script>