Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fb5d12d
fix: add focus bypass (ART 9814)
AlexCLeduc Aug 27, 2025
af035f1
fix: add translation for alt text of canada symbol (ART 9840)
AlexCLeduc Aug 27, 2025
87abe76
more translations, but also move manage-users off limits (only super-…
AlexCLeduc Aug 27, 2025
63bd2aa
wrap remaining tables in table-responsive
AlexCLeduc Aug 27, 2025
1670501
fix: Add lang attribute to language toggle link (ART 9826)
AlexCLeduc Aug 27, 2025
376d5dc
fix: french labels for male/female dim values (ART 9952)
AlexCLeduc Aug 27, 2025
dec0ab4
fix: use lang-specific name when referring to indicators by name (ART…
AlexCLeduc Aug 27, 2025
de6ac8b
format files
AlexCLeduc Aug 27, 2025
e82b690
fix: missing translation (ART 9908)
AlexCLeduc Aug 27, 2025
ec70734
fix: add country translations (ART 9908)
AlexCLeduc Aug 27, 2025
fb08d36
fix: on-add, focus on newly added dynamic form's first input (ART 9911)
AlexCLeduc Aug 28, 2025
7d17817
improve focus-ring, increase contrast on unfocused inputs
AlexCLeduc Aug 28, 2025
fd92b3a
unrelated: format all files
AlexCLeduc Aug 28, 2025
218ff09
fix: proper use of fieldset around checkbox fields (ART-9991)
AlexCLeduc Aug 29, 2025
9290adc
fix: proper labels on ckeditor iframes and bodies (also, upgrade cked…
AlexCLeduc Aug 29, 2025
c8a8e57
fix: link error messages to form inputs via aria-describedby
AlexCLeduc Sep 4, 2025
16d5f42
format
AlexCLeduc Sep 4, 2025
c1322ee
Merge branch 'main' into a11y-fixes
AlexCLeduc Jan 5, 2026
04ce4e0
move trend/benchmarking form JS to their own files
AlexCLeduc Jan 5, 2026
7be6641
fix: add form labels to tabular inputs in trend/benchmarking (ART-99…
AlexCLeduc Jan 6, 2026
35d0cdc
woops, forgot to fix conflicts, also add tabindex on table-responsive
AlexCLeduc Jan 6, 2026
5bd509e
Merge branch 'main' into a11y-fixes
AlexCLeduc Jan 6, 2026
0fc970c
Add selenium tests (#448)
AlexCLeduc Jan 7, 2026
b2a3dc4
Merge branch 'main' into a11y-fixes
AlexCLeduc Jan 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,11 @@ From the `server/` directory run the following
3. `python -m http.server 1337`
4. visit `http://localhost:1337/htmlcov/` and dig into modules to see which individual line coverage


## Selenium tests

There are a few tests that use a live browser to test interaction. These do not run by default. You'll have to run them via `python manage.py test --selenium tests/selenium/`.

These tests should work both in postgres and sqlite. But when using postgres, if anything goes wrong, the DB may not reset correctly and you may have to reset it (see dropdb test db command above).

You can run regular tests or these tests, never both at the same time. Do not attempt to run regular tests with --selenium or selenium tests without it, or else it will error and you will need to reset the test DB.
4 changes: 2 additions & 2 deletions server/cpho/fixtures/dimension_lookups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
fields:
dimension_type: 1
name_en: Male
name_fr: Male
name_fr: Mâle
value: m
excel_code: "MALES"
order: 0.0
Expand All @@ -113,7 +113,7 @@
fields:
dimension_type: 1
name_en: Female
name_fr: Female
name_fr: Femelle
value: f
excel_code: "FEMALES"
order: 1.0
Expand Down
13 changes: 8 additions & 5 deletions server/cpho/jinja2/base.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
{% block extra_scripts_css %}{% endblock %}
</head>
<body hx-ext="morph">
<a class="visually-hidden-focusable" href="#main-content" id="skip-link">{{ tm("skip_to_main") }}</a>
{{ phac_aspc.phac_aspc_wet_session_timeout_dialog(dict(request=request) , 'logout') }}
<div id="modal-moint-point"></div>
<script>
Expand Down Expand Up @@ -74,14 +75,16 @@
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation">
aria-label="{{ tm('toggle_navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
{% block header_menu %}<!-- This block will be replaced by per-page overrides -->{% endblock %}
<ul class="navbar-nav flex-fill justify-content-end">
<li class="nav-item">
<a class="nav-link text-white" href="{{ url_to_other_lang() }}">{{ get_other_lang() }}</a>
<a class="nav-link text-white"
lang="{{ get_other_lang_code() }}"
href="{{ url_to_other_lang() }}">{{ get_other_lang() }}</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item dropdown">
Expand Down Expand Up @@ -127,7 +130,7 @@
</div>
</nav>
{% endblock %}
<main class="pb-5">
<main id="main-content" class="pb-5">
{% if messages %}
{% for message in messages %}
<div role="alert"
Expand All @@ -138,7 +141,7 @@
<div id="content" class='container'>
{% block content_breadcrumbs_container %}
{# this is just here so templates can opt-out from breadcrumbs #}
<nav aria-label="breadcrumb">
<nav aria-label="{{ tm('breadcrumb_trail') }}">
<ol class="breadcrumb">
{% block content_breadcrumbs %}
{% endblock content_breadcrumbs %}
Expand Down Expand Up @@ -166,7 +169,7 @@
tabindex="-1"
role="img"
data="{{ static('third_party/img/wmms-blk.svg') }}"
aria-label="Symbol of the Government of Canada"
aria-label="{{ tm('symbol_of_the_government_of_canada') }}"
style="height: 2rem;
margin: 1rem 0"></object>
</div>
Expand Down
115 changes: 51 additions & 64 deletions server/cpho/jinja2/benchmarking/manage_benchmarking_data.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -7,68 +7,79 @@
{{ bc.item(tm("benchmarking") , None, True) }}
{% endblock %}

{% macro benchmarking_form_field_with_errors(field) %}
{{ field }}
{% macro benchmarking_form_field_with_errors(form,field,row_label_id) %}
{{ field.as_widget(attrs={"aria-labelledby": row_label_id}) }}
{% if field.errors %}
<div class="error-display">
<div class="error-display" id="{{ form.error_id_for_field(field) }}">
{% for error in field.errors %}<strong>{{ error|escape }}</strong>{% endfor %}
</div>
{% endif %}
{% endmacro %}

{% macro benchmarking_form(form) %}
{% set row_label_id = form.prefix ~ "-row-label" %}
<tr class="benchmarking-form">
<td>{{ benchmarking_form_field_with_errors(form.oecd_country) }}</td>
<td>{{ benchmarking_form_field_with_errors(form.value) }}</td>
<td>{{ form.unit }}</td>
<td>{{ benchmarking_form_field_with_errors(form.year) }}</td>
<td>
{{ benchmarking_form_field_with_errors(form,form.oecd_country, row_label_id) }}
<span id="{{ row_label_id }}" class="visually-hidden">
<span class="country-name"></span>
</span>
</td>
<td>{{ benchmarking_form_field_with_errors(form,form.value, row_label_id) }}</td>
<td>{{ form.unit.as_widget(attrs={"aria-labelledby": row_label_id}) }}</td>
<td>{{ benchmarking_form_field_with_errors(form,form.year, row_label_id) }}</td>
{# <td>{{ benchmarking_form_field_with_errors(form.standard_deviation) }}</td> #}
<td>{{ benchmarking_form_field_with_errors(form.comparison_to_oecd_avg) }}</td>
<td>{{ form.labels }}</td>
<td>{{ form.methodology_differences }}</td>
<td>{{ benchmarking_form_field_with_errors(form, form.comparison_to_oecd_avg, row_label_id) }}</td>
<td>{{ form.labels.as_widget(attrs={"aria-labelledby": row_label_id}) }}</td>
<td>{{ form.methodology_differences.as_widget(attrs={"aria-labelledby": row_label_id}) }}</td>
<td>
{{ form.is_deleted }}
{{ form.is_deleted.as_widget(attrs={"aria-labelledby": row_label_id}) }}
{{ form.id }}
</td>
</tr>
{% endmacro %}

{% block content %}
<div class="h2">{{ tm("benchmarking_metadata") }} {{ tm("for") }} : {{ indicator.name }}</div>
<div class="h2">{{ tm("benchmarking_metadata") }} {{ tm("for") }} : {{ indicator.bilingual_name }}</div>

<a class="btn btn-primary"
href="{{ url('export_benchmarking', args=[indicator.id]) }}">Export Benchmarking</a>
href="{{ url('export_benchmarking', args=[indicator.id]) }}">{{ tm("export_benchmarking") }}</a>

<table class="d-none benchmarking-empty-form-container">
{{ benchmarking_form(benchmarking_formset.empty_form) }}
</table>
<div class="table-responsive">

<table class="d-none benchmarking-empty-form-container">
{{ benchmarking_form(benchmarking_formset.empty_form) }}
</table>
</div>
<form action="." method="post">
{{ benchmarking_formset.management_form }}
{{ csrf_input }}

<table class="table mt-3"
id="benchmarking-table"
style="overflow-x:auto;
display:block">
<thead>
<tr>
<th>{{ tm("oecd_country") }}</th>
<th>{{ tm("value") }}</th>
<th>{{ tm("unit") }}</th>
<th>{{ tm("year") }}</th>
{# <th>{{ tdt("Standard Deviation") }}</th> #}
<th>{{ tm("comparison_to_oecd_average") }}</th>
<th>{{ tm("labels") }}</th>
<th>{{ tm("methodology_differences") }}</th>
<th>{{ tm("delete") }}</th>
</tr>
</thead>
<tbody id="benchmarking-table-body"
class="text-center benchmarking-form-list">
{% for form in benchmarking_formset %}{{ benchmarking_form(form) }}{% endfor %}
</tbody>
</table>
<div class="table-responsive">

<table class="table mt-3"
id="benchmarking-table"
style="overflow-x:auto;
display:block">
<thead>
<tr>
<th>{{ tm("oecd_country") }}</th>
<th>{{ tm("value") }}</th>
<th>{{ tm("unit") }}</th>
<th>{{ tm("year") }}</th>
{# <th>{{ tdt("Standard Deviation") }}</th> #}
<th>{{ tm("comparison_to_oecd_average") }}</th>
<th>{{ tm("labels") }}</th>
<th>{{ tm("methodology_differences") }}</th>
<th>{{ tm("delete") }}</th>
</tr>
</thead>
<tbody id="benchmarking-table-body"
class="text-center benchmarking-form-list">
{% for form in benchmarking_formset %}{{ benchmarking_form(form) }}{% endfor %}
</tbody>
</table>
</div>
{% if benchmarking_formset.non_form_errors() %}
<div class="error-div">{{ benchmarking_formset.non_form_errors() }}</div>
{% endif %}
Expand All @@ -82,31 +93,7 @@
{% endif %}
</form>

<script>
let addButton = document.querySelector("#add-form");
if (addButton){
addButton.addEventListener('click', addForm);
}

function addForm(e) {
let forms = document.querySelectorAll(".benchmarking-form-list > .benchmarking-form");
let newFormIndex = forms.length;
let numForms = forms.length + 1;
let formTemplateNode = document.querySelector(".benchmarking-empty-form-container");
let container = document.querySelector(".benchmarking-form-list");
let totalFormsInput = document.querySelector("#id_benchmarking-TOTAL_FORMS"); //management form inputs

e.preventDefault();
let formRegex = RegExp(`benchmarking-__prefix__-`,'g')
console.log(formRegex);
let newFormHtml = formTemplateNode.innerHTML.replace(formRegex, `benchmarking-${newFormIndex}-`)

let newForm = document.createElement("tr")
newForm.classList.add("benchmarking-form")
newForm.innerHTML = newFormHtml;
container.appendChild(newForm)
totalFormsInput.setAttribute('value', `${numForms}`)
}
</script>
<script src="{{ static('js/manage_benchmarking_scripts.js') }}"
type="text/javascript"></script>

{% endblock %}
2 changes: 1 addition & 1 deletion server/cpho/jinja2/breadcrumb_macros.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
{% endmacro %}

{% macro indicator(indicator, active) %}
{{ item(indicator.name , url('view_indicator', args=[indicator.id]) , active) }}
{{ item(indicator.bilingual_name , url('view_indicator', args=[indicator.id]) , active) }}
{% endmacro %}

{% macro indicator_period(indicator, period, active) %}
Expand Down
131 changes: 67 additions & 64 deletions server/cpho/jinja2/changelog/changelog_macros.jinja2
Original file line number Diff line number Diff line change
@@ -1,72 +1,75 @@
{% from 'generic_macros.jinja2' import date_display %}

{% macro changelog_table(edit_entries, show_model_type=True, show_user=True) %}
<table id="changelog-table"
style="width:100%"
cellspacing="15"
class="table table-striped">
<thead class="thead-dark">
<tr>
<th>{{ tm("date") }}</th>
{% if show_user %}<th>{{ tm("author") }}</th>{% endif %}
<th>{{ tm("action") }}</th>
{% if show_model_type %}<th>{{ tm("object_type") }}</th>{% endif %}
<th>{{ tm("name") }}</th>
<th>{{ tm("field") }}</th>
<th>{{ tm("previous_change") }}</th>
<th>{{ tm("this_change") }}</th>
</tr>
</thead>
<tbody>
{% for edit_entry in edit_entries %}
{% if not edit_entry.diffs %}
<tr>
<td>{{ date_display(edit_entry.right_version.timestamp) }}</td>
{% if show_user %}
<td>
{% if edit_entry.author %}
{{ edit_entry.author.pretty_name }}
{% else %}
{{ tm("n/a") }}
{% endif %}
</td>
{% endif %}
<td class='font-weight-bold'>{{ tm("saved") }}</td>
{% if show_model_type %}<td>{{ edit_entry.eternal._meta.verbose_name }}</td>{% endif %}
<td>{{ edit_entry.live_name }}</td>
<td colspan="3">{{ tm("no_change_detected_compared_to_previous_version") }}</td>
</tr>
{% endif %}
{% for diff in edit_entry.diffs %}
<tr>
<td>{{ date_display(edit_entry.right_version.timestamp) }}</td>
{% if show_user %}
<div class="table-responsive">

<table id="changelog-table"
style="width:100%"
cellspacing="15"
class="table table-striped">
<thead class="thead-dark">
<tr>
<th>{{ tm("date") }}</th>
{% if show_user %}<th>{{ tm("author") }}</th>{% endif %}
<th>{{ tm("action") }}</th>
{% if show_model_type %}<th>{{ tm("object_type") }}</th>{% endif %}
<th>{{ tm("name") }}</th>
<th>{{ tm("field") }}</th>
<th>{{ tm("previous_change") }}</th>
<th>{{ tm("this_change") }}</th>
</tr>
</thead>
<tbody>
{% for edit_entry in edit_entries %}
{% if not edit_entry.diffs %}
<tr>
<td>{{ date_display(edit_entry.right_version.timestamp) }}</td>
{% if show_user %}
<td>
{% if edit_entry.author %}
{{ edit_entry.author.pretty_name }}
{% else %}
{{ tm("n/a") }}
{% endif %}
</td>
{% endif %}
<td class='font-weight-bold'>{{ tm("saved") }}</td>
{% if show_model_type %}<td>{{ edit_entry.eternal._meta.verbose_name }}</td>{% endif %}
<td>{{ edit_entry.live_name }}</td>
<td colspan="3">{{ tm("no_change_detected_compared_to_previous_version") }}</td>
</tr>
{% endif %}
{% for diff in edit_entry.diffs %}
<tr>
<td>{{ date_display(edit_entry.right_version.timestamp) }}</td>
{% if show_user %}
<td>
{% if edit_entry.author %}
{{ edit_entry.author.pretty_name }}
{% else %}
{{ tm("n/a") }}
{% endif %}
</td>
{% endif %}
<td class='font-weight-bold'>{{ diff.action }}</td>
{% if show_model_type %}<td>{{ edit_entry.eternal._meta.verbose_name }}</td>{% endif %}
<td>{{ edit_entry.live_name }}</td>
<td>
{% if edit_entry.author %}
{{ edit_entry.author.pretty_name }}
{% else %}
{{ tm("n/a") }}
{% endif %}
{% if diff.field %}{{ diff.field.verbose_name }}{% endif %}
</td>
{% endif %}
<td class='font-weight-bold'>{{ diff.action }}</td>
{% if show_model_type %}<td>{{ edit_entry.eternal._meta.verbose_name }}</td>{% endif %}
<td>{{ edit_entry.live_name }}</td>
<td>
{% if diff.field %}{{ diff.field.verbose_name }}{% endif %}
</td>
{###############autoescape content is escaped ######################}
{% autoescape false %}
<td>{{ diff.get_before_diff() }}</td>
{% endautoescape %}
{% autoescape false %}
<td>{{ diff.get_after_diff() }}</td>
{% endautoescape %}
{% block extra_columns %}{% endblock %}
</tr>
{###############autoescape content is escaped ######################}
{% autoescape false %}
<td>{{ diff.get_before_diff() }}</td>
{% endautoescape %}
{% autoescape false %}
<td>{{ diff.get_after_diff() }}</td>
{% endautoescape %}
{% block extra_columns %}{% endblock %}
</tr>
{% endfor %}
{% endfor %}
{% endfor %}
</tbody>
</table>
</tbody>
</table>
</div>

{% endmacro %}
Loading