diff --git a/scoring/filters.py b/scoring/filters.py index f06a895f7..735e831ca 100644 --- a/scoring/filters.py +++ b/scoring/filters.py @@ -63,7 +63,7 @@ class QuestionScoreFilter(django_filters.FilterSet): ) population = django_filters.ChoiceFilter( - field_name="plans_core__population", + field_name="plan_score__population", choices=PlanScore.POPULATION_ALL_FILTER_CHOICES, ) @@ -73,6 +73,15 @@ class QuestionScoreFilter(django_filters.FilterSet): control = django_filters.CharFilter(field_name="plan_score__political_control") + region = django_filters.ChoiceFilter( + field_name="plan_score__council__region", choices=Council.REGION_CHOICES + ) + + county = django_filters.ChoiceFilter( + field_name="plan_score__council__county", + choices=Council.get_county_choices(), + ) + class Meta: model = PlanQuestionScore fields = [] diff --git a/scoring/models.py b/scoring/models.py index 48c1b5d6e..4b345a36b 100644 --- a/scoring/models.py +++ b/scoring/models.py @@ -717,6 +717,19 @@ def get_scores_breakdown(self, year=None, scoring_group=None): return counts + def get_score_breakdown_for_councils(self, council_ids, year): + counts = ( + PlanQuestionScore.objects.filter( + plan_score__year=year, + plan_question=self, + plan_score__council_id__in=council_ids, + ) + .values("score") + .annotate(score_count=Count("id")) + ) + + return counts + class PlanQuestionScore(ScoreFilterMixin, models.Model): """ diff --git a/scoring/static/scoring/js/main.js b/scoring/static/scoring/js/main.js index d6596f47f..e62dd1983 100644 --- a/scoring/static/scoring/js/main.js +++ b/scoring/static/scoring/js/main.js @@ -73,82 +73,126 @@ updateUIFromHashState(); // Monitor for future changes of the hash state window.addEventListener('hashchange', updateUIFromHashState); -forEachElement('.js-location-search-autocomplete', function(input){ - var ac = new Awesomplete( - input, - { - list: councils.map(function(council){ - return council.name; - }), - minChars: 3, - autoFirst: true - } - ); - input.parentNode.addEventListener('awesomplete-select', function(data){ - data.preventDefault(); - var council = findItem(councils, {'name': data.text }); - window.location.href = council['council_url']; +function setUpAutocompletes() { + forEachElement('.js-location-search-autocomplete', function(input){ + var ac = new Awesomplete( + input, + { + list: councils.map(function(council){ + return council.name; + }), + minChars: 3, + autoFirst: true + } + ); + input.parentNode.addEventListener('awesomplete-select', function(data){ + data.preventDefault(); + var council = findItem(councils, {'name': data.text }); + window.location.href = council['council_url']; + }); + input.placeholder = 'Council name or postcode'; + }); + + forEachElement('.js-location-jump-autocomplete', function(input){ + var ac = new Awesomplete( + input, + { + list: councils.map(function(council){ + return council.name; + }), + minChars: 3, + autoFirst: true + } + ); + input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ + var council = findItem(councils, {'name': data.text }); + window.location.href = council.scoring_url + '#' + serialiseObject({ + 'jump': council.slug + }); + }); }); - input.placeholder = 'Council name or postcode'; -}); -forEachElement('.js-location-jump-autocomplete', function(input){ - var ac = new Awesomplete( - input, - { - list: councils.map(function(council){ - return council.name; - }), - minChars: 3, - autoFirst: true - } - ); - input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ - var council = findItem(councils, {'name': data.text }); - window.location.href = council.scoring_url + '#' + serialiseObject({ - 'jump': council.slug + forEachElement('.js-question-jump-autocomplete', function(input){ + var ac = new Awesomplete( + input, + { + list: councils.map(function(council){ + return council.name; + }), + minChars: 3, + autoFirst: true + } + ); + input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ + var council = findItem(councils, {'name': data.text }); + window.location.href = window.location.pathname + '?type=' + council.council_type + '#' + serialiseObject({ + 'jump': council.slug + }); }); }); -}); -forEachElement('.js-question-jump-autocomplete', function(input){ - var ac = new Awesomplete( - input, - { - list: councils.map(function(council){ - return council.name; - }), - minChars: 3, - autoFirst: true - } - ); - input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ - var council = findItem(councils, {'name': data.text }); - window.location.href = window.location.pathname + '?type=' + council.council_type + '#' + serialiseObject({ - 'jump': council.slug + forEachElement('.js-location-compare-autocomplete', function(input){ + var council_type = input.dataset.council_type; + var ac = new Awesomplete( + input, + { + list: councils.filter(function(council){ + if (typeof council_type === "undefined") { return true; } + if (council.council_type === council_type) { return true; } + return false; + }).map(function(council) { return council.name; }), + minChars: 3, + autoFirst: true + } + ); + + input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ + handleCouncilSelection(data.text); }); }); -}); -forEachElement('.js-location-compare-autocomplete', function(input){ - var council_type = input.dataset.council_type; - var ac = new Awesomplete( - input, - { - list: councils.filter(function(council){ - if (typeof council_type === "undefined") { return true; } - if (council.council_type === council_type) { return true; } - return false; - }).map(function(council) { return council.name; }), - minChars: 3, - autoFirst: true - } - ); + forEachElement('.js-methodology-council-autocomplete', function(input){ + var ac = new Awesomplete( + input, + { + list: councils.map(function(council){ + return council.name; + }), + minChars: 3, + autoFirst: true + } + ); + input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ + var council = findItem(councils, {'name': data.text }); + console.log(council); + var container = document.querySelector('.js-dynamic-content'); + container.setAttribute('data-methodology-active-council-type', council.council_type); + }); + }); - input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ - handleCouncilSelection(data.text); + forEachElement('.js-section-council-autocomplete', function(input){ + var ac = new Awesomplete( + input, + { + list: councils.map(function(council){ + return council.name; + }), + minChars: 3, + autoFirst: true + } + ); + input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ + var council = findItem(councils, {'name': data.text }); + var sp = new URLSearchParams(window.location.search) + sp.delete('type'); + sp.delete('council'); + sp.append('council', council.slug); + window.location.href = window.location.pathname + '?' + sp.toString() + '#questions'; + }); }); -}); +} + +setUpAutocompletes(); // Function to handle selection from both autocomplete and suggestions function handleCouncilSelection(councilName) { @@ -388,46 +432,6 @@ forEachElement('[data-methodology-switch-council-type]', function(trigger){ }); }); -forEachElement('.js-methodology-council-autocomplete', function(input){ - var ac = new Awesomplete( - input, - { - list: councils.map(function(council){ - return council.name; - }), - minChars: 3, - autoFirst: true - } - ); - input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ - var council = findItem(councils, {'name': data.text }); - console.log(council); - var container = document.querySelector('.js-dynamic-content'); - container.setAttribute('data-methodology-active-council-type', council.council_type); - }); -}); - -forEachElement('.js-section-council-autocomplete', function(input){ - var ac = new Awesomplete( - input, - { - list: councils.map(function(council){ - return council.name; - }), - minChars: 3, - autoFirst: true - } - ); - input.parentNode.addEventListener('awesomplete-selectcomplete', function(data){ - var council = findItem(councils, {'name': data.text }); - var sp = new URLSearchParams(window.location.search) - sp.delete('type'); - sp.delete('council'); - sp.append('council', council.slug); - window.location.href = window.location.pathname + '?' + sp.toString() + '#questions'; - }); -}); - // Previous year comparison toggle on council page forEachElement('#js-toggle-previous-year-score', function(el) { el.addEventListener('change', function() { @@ -480,16 +484,15 @@ function setUpMobileCategorySelect() { } setUpMobileCategorySelect(); -function ajaxLoadCouncilTypeScorecard(url) { +function ajaxLoadPageFragments(url) { const selectors = [ - '#home-page-main-filter', + '#main-filter', '.scorecard-table', - '.js-category-select-form' + '.js-category-select-form', + '.question-performance' ]; - selectors.forEach(selector => { - document.querySelector(selector)?.classList.add('loading-shimmer'); - }); + document.documentElement.classList.add('loading-shimmer'); fetch(url) .then(response => response.text()) @@ -505,9 +508,13 @@ function ajaxLoadCouncilTypeScorecard(url) { } }); + document.documentElement.classList.remove('loading-shimmer'); + setUpTableSorting(); showOrHideYearDifference(); setUpMobileCategorySelect(); + setUpAutocompletes(); + setUpImprovedWorsenedCouncilCheckboxes(); const advancedFilter = document.querySelector('#advancedFilter'); if (advancedFilter) { @@ -524,7 +531,7 @@ function ajaxLoadCouncilTypeScorecard(url) { function handleFilterChange(e) { e.preventDefault(); - const mainForm = document.getElementById('home-page-main-filter'); + const mainForm = document.getElementById('main-filter'); if (!mainForm) return; const formData = new FormData(mainForm); @@ -536,7 +543,7 @@ function handleFilterChange(e) { const url = `${baseUrl}?${params.toString()}`; history.pushState({}, '', url); - ajaxLoadCouncilTypeScorecard(url); + ajaxLoadPageFragments(url); } if (typeof window.fetch !== 'undefined') { @@ -545,21 +552,21 @@ if (typeof window.fetch !== 'undefined') { e.preventDefault(); const href = e.target.href; history.pushState({}, '', href); - ajaxLoadCouncilTypeScorecard(href); + ajaxLoadPageFragments(href); } }); // Handle form submission (Apply filters button) document.addEventListener('submit', e => { - if (e.target.matches('#home-page-main-filter')) { + if (e.target.matches('#main-filter')) { handleFilterChange(e); } }); // Handle radio buttons and select changes document.addEventListener('change', e => { - if (e.target.matches('#home-page-main-filter input[type="radio"]') || - e.target.matches('#home-page-main-filter select')) { + if (e.target.matches('#main-filter input[type="radio"]') || + e.target.matches('#main-filter select')) { handleFilterChange(new Event('submit')); } }); @@ -569,7 +576,7 @@ if (typeof window.fetch !== 'undefined') { if (e.target.matches('#resetButton')) { e.preventDefault(); - const mainForm = document.getElementById('home-page-main-filter'); + const mainForm = document.getElementById('main-filter'); if (mainForm) { // Reset radio buttons mainForm.querySelectorAll('input[type="radio"]').forEach(radio => { @@ -597,7 +604,7 @@ if (typeof window.fetch !== 'undefined') { window.addEventListener('popstate', e => { const url = new URL(window.location.href); if (councilTypePaths.includes(url.pathname)) { - ajaxLoadCouncilTypeScorecard(window.location.href); + ajaxLoadPageFragments(window.location.href); } }); } @@ -651,26 +658,30 @@ function updateTableVisibility() { }); } -forEachElement('.js-checkbox-improved-councils', function(checkbox) { - checkbox.addEventListener('change', function() { - // If this checkbox is checked, uncheck the other one - if (this.checked) { - forEachElement('.js-checkbox-worsened-councils', function(otherCheckbox) { - otherCheckbox.checked = false; - }); - } - updateTableVisibility(); +function setUpImprovedWorsenedCouncilCheckboxes() { + forEachElement('.js-checkbox-improved-councils', function(checkbox) { + checkbox.addEventListener('change', function() { + // If this checkbox is checked, uncheck the other one + if (this.checked) { + forEachElement('.js-checkbox-worsened-councils', function(otherCheckbox) { + otherCheckbox.checked = false; + }); + } + updateTableVisibility(); + }); }); -}); -forEachElement('.js-checkbox-worsened-councils', function(checkbox) { - checkbox.addEventListener('change', function() { - // If this checkbox is checked, uncheck the other one - if (this.checked) { - forEachElement('.js-checkbox-improved-councils', function(otherCheckbox) { - otherCheckbox.checked = false; - }); - } - updateTableVisibility(); + forEachElement('.js-checkbox-worsened-councils', function(checkbox) { + checkbox.addEventListener('change', function() { + // If this checkbox is checked, uncheck the other one + if (this.checked) { + forEachElement('.js-checkbox-improved-councils', function(otherCheckbox) { + otherCheckbox.checked = false; + }); + } + updateTableVisibility(); + }); }); -}); +} + +setUpImprovedWorsenedCouncilCheckboxes(); diff --git a/scoring/static/scoring/scss/loading-shimmer.scss b/scoring/static/scoring/scss/loading-shimmer.scss index 7e5402320..97af8df7e 100644 --- a/scoring/static/scoring/scss/loading-shimmer.scss +++ b/scoring/static/scoring/scss/loading-shimmer.scss @@ -1,4 +1,13 @@ -.loading-shimmer { +@keyframes shimmer { + 0% { + background-position: right; + } + 100% { + background-position: left; + } +} + +%loading-shimmer { position: relative; filter: grayscale(50%); opacity: 0.5; @@ -15,13 +24,15 @@ background-size: 300% 100%; animation: shimmer 2s infinite; } +} - @keyframes shimmer { - 0% { - background-position: right; - } - 100% { - background-position: left; - } +.loading-shimmer { + #main-filter, + .scorecard-table, + .js-category-select-form, + .question-performance > h3 .text-muted, + .question-performance .card, + .table-council-question-performance { + @extend %loading-shimmer; } } diff --git a/scoring/static/scoring/scss/methodology.scss b/scoring/static/scoring/scss/methodology.scss index 2e76a99e6..73984dc31 100644 --- a/scoring/static/scoring/scss/methodology.scss +++ b/scoring/static/scoring/scss/methodology.scss @@ -84,6 +84,16 @@ $council-types: ( .radio-btn { margin: 0 !important; } + + .btn:last-of-type { + margin-right: auto; // push searchbar/autocomplete to the right + } + + .searchbar { + width: 100%; + max-width: 20em; + border-color: #999; + } } .question-card--removed { diff --git a/scoring/templates/scoring/includes/advanced-filter.html b/scoring/templates/scoring/includes/advanced-filter.html index 0395888a9..60ac95dfb 100644 --- a/scoring/templates/scoring/includes/advanced-filter.html +++ b/scoring/templates/scoring/includes/advanced-filter.html @@ -1,5 +1,3 @@ -
Or show scores by type of council
-{{ question_removed.reason }}
{{ question_removed.reason }}
-There is no comparison between {{ plan_year }} and {{ previous_year }} data because this question's maximum score was modified in {{ plan_year }}.
-It is not possible to compare performance on this question between {{ plan_year }} and {{ previous_year }} because this question’s maximum score was modified in {{ plan_year }}.
{% elif comparison_overridden %} -There is no comparison between {{ plan_year }} and {{ previous_year }} data because this question was modified in {{ plan_year }}.
-It is not possible to compare performance on this question between {{ plan_year }} and {{ previous_year }} data because this question was modified in {{ plan_year }}.
{% elif no_comparison %} -This question was introduced in the {{ plan_year }} Action Scorecards and has no historical data for comparison.
-{% include 'scoring/includes/scoring-group-name.html' with group=scoring_group.slug plural=1 %}
+This question was introduced in the {{ plan_year }} Action Scorecards and has no historical data for comparison.
+ {% else %} +Note: “in {{ previous_year }}” counts show how the councils listed below were marked on this question in {{ previous_year }}. This list of councils may be slightly different to the list of councils originally assessed on this question in {{ previous_year }}, due to the creation and abolition of councils{% if filter_params.ruc_cluser or filter_params.population or filter_params.imdq or filter_params.control %}, or changes in your filtered properties{% endif %} between Scorecard years.
+ {% endif %} + + {% if not max_score_changed and not comparison_overridden and not no_comparison and not question.is_negatively_marked %} +Try adjusting your filter criteria or + + clear all filters.
+
{% if score.score != 0 %}
-
|