diff --git a/bitpoll/base/static/js/main.js b/bitpoll/base/static/js/main.js index 63b75559..b1a0dd6f 100644 --- a/bitpoll/base/static/js/main.js +++ b/bitpoll/base/static/js/main.js @@ -3,6 +3,7 @@ $(document).ready(function() { $(".script-only").css("display", "block"); $("a.script-only").css("display", "inline-block"); $("button.script-only").css("display", "inline-block"); + $("span.script-only").css("display", "inline"); $("td.script-only").css("display", "table-cell"); $("tr.script-only").css("display", "table-row"); $("table.script-only").css("display", "table"); diff --git a/bitpoll/base/static/js/poll_filter.js b/bitpoll/base/static/js/poll_filter.js new file mode 100644 index 00000000..655a80c3 --- /dev/null +++ b/bitpoll/base/static/js/poll_filter.js @@ -0,0 +1,107 @@ +var scores; + +$(function() { + // Collect scores for all vote choices + scores = [] + $("#scores .choice-sum").each(function () { + // "n/a" should be treated like 0% + scores.push(parseFloat($(this).data("score")) || 0.0); + }); + + // Event handler + $("#filter-threshold-percent").on("input", filterUpdatePercent); + $("#filter-threshold-count").on("input", filterUpdateCount); + $("#filter-apply").on("click", filterUpdatePercent); + $("#filter-reset").on("click", filterReset); + + // Fill form inputs with total count + filterReset(); +}); + +function filterColumns(keepCount) { + var threshold = $("#filter-threshold-percent").val() || 0.0; + + // Identify filtered columns + var count = 0; + var filteredColumns = [true]; // Always show first column (vote author) + scores.forEach(function (score) { + if (score >= threshold) { + filteredColumns.push(true); + count++; + } else { + filteredColumns.push(false); + } + }); + filteredColumns.push(true); // Always show last column (edit, impersonate) + + if (!keepCount) { + $("#filter-threshold-count").val(count); + } + + filterSetVisibleColumns(filteredColumns); + + return count != scores.length; +} + +function filterCountToPercent(count) { + if (count <= 0) return 100; + if (scores.length <= count) return 0; + var sorted = scores.slice(); + sorted.sort((a, b) => a - b); + return sorted[sorted.length - count]; +} + +function filterReset() { + // count will be automatically set by filterUpdate + $("#filter-threshold-percent").val(0); + filterUpdate(); +} + +function filterSetVisibleColumns(columns) { + // Remove old filtering + $("[data-original-colspan]").each(function () { + $(this).attr("colspan", $(this).attr("data-original-colspan")); + }); + $(".filtered").removeClass("filtered"); + + // Set new filtering + $("#poll tr").each(function () { + var columnIdx = 0; + $(this).find("td, th").each(function () { + var colspan = parseInt($(this).attr("data-original-colspan") ?? $(this).attr("colspan") ?? "1"); + + var visible = columns.slice(columnIdx, columnIdx + colspan).filter(x => x).length; + if (visible > 0) { + $(this).attr("data-original-colspan", $(this).attr("colspan")); + $(this).attr("colspan", visible); + } else { + $(this).addClass("filtered"); + } + + columnIdx += colspan; + }); + }); +} + +function filterUpdate(keepCount) { + var isFiltered = filterColumns(keepCount) + + if (isFiltered) { + $("#filterLink").addClass("hidden"); + $("#filterLinkWarning").removeClass("hidden"); + } else { + $("#filterLink").removeClass("hidden"); + $("#filterLinkWarning").addClass("hidden"); + } +} + +function filterUpdateCount() { + var count = parseInt($("#filter-threshold-count").val()); + var threshold = filterCountToPercent(count); + $("#filter-threshold-percent").val(threshold); + filterUpdate(true); +} + +function filterUpdatePercent() { + filterUpdate(false); +} diff --git a/bitpoll/base/static/scss/main.scss b/bitpoll/base/static/scss/main.scss index ba80edd8..ea3eaac9 100644 --- a/bitpoll/base/static/scss/main.scss +++ b/bitpoll/base/static/scss/main.scss @@ -60,7 +60,7 @@ html, body, h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6, input, textare html, body { - margin:0; + margin:0 !important; padding:0; height:100%; } diff --git a/bitpoll/poll/templates/poll/poll.html b/bitpoll/poll/templates/poll/poll.html index a3a876c4..c3266b46 100644 --- a/bitpoll/poll/templates/poll/poll.html +++ b/bitpoll/poll/templates/poll/poll.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load pipeline %} {% load i18n %} {% load poll_filter vote_permissions comment_permissions poll_permissions %} {% load tz %} @@ -149,7 +150,7 @@ {% if summary %} - {% trans 'Scores' %}
+ {% trans 'Percentage' %}
{# {% set scores, counts, totals, max_score = poll.get_stats() %}#} {% for choice in stats %} @@ -211,10 +212,70 @@ {# TODO: Add legend for choice values #} -
+
+ + {% trans 'Filter' %} + · + + {# Highlight link if poll results are filtered #} + {% trans 'Export as CSV' %}
+ +

{% if comments %}

{% trans 'Comments' %}

{% endif %}
{% for comment in comments %} @@ -254,3 +315,7 @@

{% trans 'Post a comment' %}

{% endblock %} + +{% block additionalJS %} + {% javascript 'poll_view' %} +{% endblock %} diff --git a/bitpoll/settings.py b/bitpoll/settings.py index 99d905a9..47c70597 100644 --- a/bitpoll/settings.py +++ b/bitpoll/settings.py @@ -186,6 +186,12 @@ ), 'output_filename': 'js/poll_edit.js', }, + 'poll_view': { + 'source_filenames': ( + 'js/poll_filter.js', + ), + 'output_filename': 'js/poll_view.js', + }, 'base_late': { 'source_filenames': ( #'js/lib/jquery-range.min.js', # TODO: is this needet for the numeric polls? diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index d9963225..20d86573 100644 --- a/locale/de_DE/LC_MESSAGES/django.po +++ b/locale/de_DE/LC_MESSAGES/django.po @@ -1491,23 +1491,45 @@ msgstr "Weise einen User zu" msgid "Vote" msgstr "Abstimmen" -#: bitpoll/poll/templates/poll/poll.html:153 -msgid "Scores" -msgstr "Auswertungen" +#: bitpoll/poll/templates/poll/poll.html:154 +msgid "Percentage" +msgstr "Prozentsatz" -#: bitpoll/poll/templates/poll/poll.html:171 -#: bitpoll/poll/templates/poll/poll.html:186 +#: bitpoll/poll/templates/poll/poll.html:172 +#: bitpoll/poll/templates/poll/poll.html:187 msgid "Score" -msgstr "Auswertung" +msgstr "Punktzahl" #: bitpoll/poll/templates/poll/poll.html:193 msgid "Details" msgstr "Details" +#: bitpoll/poll/templates/poll/poll.html:218 +#: bitpoll/poll/templates/poll/poll.html:225 +#: bitpoll/poll/templates/poll/poll.html:239 +msgid "Filter" +msgstr "Filter" + #: bitpoll/poll/templates/poll/poll.html:216 msgid "Export as CSV" msgstr "Als CSV exportieren" +#: bitpoll/poll/templates/poll/poll.html:246 +msgid "Minimum percentage" +msgstr "Minimaler Prozentsatz" + +#: bitpoll/poll/templates/poll/poll.html:259 +msgid "Maximum count" +msgstr "Maximale Anzahl" + +#: bitpoll/poll/templates/poll/poll.html:268 +msgid "Reset" +msgstr "Reset" + +#: bitpoll/poll/templates/poll/poll.html:272 +msgid "Done" +msgstr "Fertig" + #: bitpoll/poll/templates/poll/poll.html:219 msgid "Comments" msgstr "Kommentare" @@ -1670,7 +1692,7 @@ msgstr "Teilnehmerliste verbergen" #: bitpoll/poll/templates/poll/settings.html:137 msgid "Show score instead of percentage" -msgstr "Zeige Score statt Prozentsatz" +msgstr "Zeige Punktzahl statt Prozentsatz" #: bitpoll/poll/templates/poll/settings.html:146 msgid "" diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po index b0144da9..ce7ca35b 100644 --- a/locale/en_US/LC_MESSAGES/django.po +++ b/locale/en_US/LC_MESSAGES/django.po @@ -1415,12 +1415,12 @@ msgstr "" msgid "Vote" msgstr "Vote" -#: bitpoll/poll/templates/poll/poll.html:153 -msgid "Scores" -msgstr "Scores" +#: bitpoll/poll/templates/poll/poll.html:154 +msgid "Percentage" +msgstr "Percentage" -#: bitpoll/poll/templates/poll/poll.html:171 -#: bitpoll/poll/templates/poll/poll.html:186 +#: bitpoll/poll/templates/poll/poll.html:172 +#: bitpoll/poll/templates/poll/poll.html:187 msgid "Score" msgstr "Score" @@ -1428,10 +1428,32 @@ msgstr "Score" msgid "Details" msgstr "" +#: bitpoll/poll/templates/poll/poll.html:218 +#: bitpoll/poll/templates/poll/poll.html:225 +#: bitpoll/poll/templates/poll/poll.html:239 +msgid "Filter" +msgstr "Filter" + #: bitpoll/poll/templates/poll/poll.html:216 msgid "Export as CSV" msgstr "" +#: bitpoll/poll/templates/poll/poll.html:246 +msgid "Minimum percentage" +msgstr "Minimum percentage" + +#: bitpoll/poll/templates/poll/poll.html:259 +msgid "Maximum count" +msgstr "Maximum count" + +#: bitpoll/poll/templates/poll/poll.html:268 +msgid "Reset" +msgstr "Reset" + +#: bitpoll/poll/templates/poll/poll.html:272 +msgid "Done" +msgstr "Done" + #: bitpoll/poll/templates/poll/poll.html:219 msgid "Comments" msgstr "Comments" diff --git a/locale/it_IT/LC_MESSAGES/django.po b/locale/it_IT/LC_MESSAGES/django.po index e6926ea0..545403d8 100644 --- a/locale/it_IT/LC_MESSAGES/django.po +++ b/locale/it_IT/LC_MESSAGES/django.po @@ -1500,12 +1500,12 @@ msgstr "Assegna utente" msgid "Vote" msgstr "Vota" -#: bitpoll/poll/templates/poll/poll.html:153 -msgid "Scores" -msgstr "Punteggi" +#: bitpoll/poll/templates/poll/poll.html:154 +msgid "Percentage" +msgstr "" -#: bitpoll/poll/templates/poll/poll.html:171 -#: bitpoll/poll/templates/poll/poll.html:186 +#: bitpoll/poll/templates/poll/poll.html:172 +#: bitpoll/poll/templates/poll/poll.html:187 msgid "Score" msgstr "Punteggio" @@ -1513,10 +1513,32 @@ msgstr "Punteggio" msgid "Details" msgstr "Dettagli" +#: bitpoll/poll/templates/poll/poll.html:218 +#: bitpoll/poll/templates/poll/poll.html:225 +#: bitpoll/poll/templates/poll/poll.html:239 +msgid "Filter" +msgstr "" + #: bitpoll/poll/templates/poll/poll.html:216 msgid "Export as CSV" msgstr "Esporta come CSV" +#: bitpoll/poll/templates/poll/poll.html:246 +msgid "Minimum percentage" +msgstr "" + +#: bitpoll/poll/templates/poll/poll.html:259 +msgid "Maximum count" +msgstr "" + +#: bitpoll/poll/templates/poll/poll.html:268 +msgid "Reset" +msgstr "" + +#: bitpoll/poll/templates/poll/poll.html:272 +msgid "Done" +msgstr "" + #: bitpoll/poll/templates/poll/poll.html:219 msgid "Comments" msgstr "Commenti"