Skip to content

Commit 5ab5bdb

Browse files
committed
a11y: critère 5.1 et 5.2 des tableaux
1 parent 0c4c339 commit 5ab5bdb

File tree

8 files changed

+162
-98
lines changed

8 files changed

+162
-98
lines changed

src/components/records/State.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe("CertificationState", () => {
1818
const wrapper = mount(State, { props: {
1919
record: { 'certification_state': CertificationState.CERTIFIED, certification_date_debut: new Date('2023-01-01') }
2020
} })
21-
expect(wrapper.text()).toContain("Certifié 2023")
21+
expect(wrapper.text()).toContain("Certifié2023")
2222
expect(wrapper.attributes()).toHaveProperty('aria-label', "Certifié en 2023")
2323
})
2424
})

src/components/records/State.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<span :class="['fr-badge', stateInfo.color]" :aria-label="dateLabel ? `${stateInfo.label} en ${dateLabel}` : stateInfo.label">
3-
{{ stateInfo.label }}
4-
<span v-if="showDate && dateLabel" class="year">{{ dateLabel }}</span>
3+
<span aria-hidden>{{ stateInfo.label }}</span>
4+
<span v-if="showDate && dateLabel" class="year" aria-hidden>{{ dateLabel }}</span>
55
</span>
66
</template>
77

src/components/records/Table/FeatureGroup.vue

Lines changed: 95 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<template>
2-
<tbody>
2+
<tbody class="feature-group">
33
<tr @click.stop="open = !open" @keydown.enter="open = !open" class="clickable group-header" tabindex="0">
44
<td class="selection">
55
<div class="fr-checkbox-group single-checkbox">
66
<input type="checkbox" :id="'radio-'+ featureGroup.key" :checked="allSelected" @click="toggleFeatureGroup" />
7-
<label class="fr-label" :for="'radio-'+ featureGroup.key" />
7+
<label class="fr-label" :for="'radio-'+ featureGroup.key" :aria-label="allSelected ? `Désélectionner les parcelles ${featureGroup.label.toLocaleLowerCase()}` : `Sélectionner les parcelles ${featureGroup.label.toLocaleLowerCase()}`" />
88
</div>
99
</td>
1010
<td class="accordion"><span class="fr-icon fr-icon-arrow-down-s-line" :aria-checked="open" aria-role="button" /></td>
@@ -29,94 +29,107 @@
2929
</tr>
3030
<tr>
3131
<td colspan="7">
32-
<table class="fr-table group-table">
32+
<table class="fr-table group-table fr-table--no-caption" :aria-describedby="`operator-features-summary-${featureGroup.key}`">
33+
<caption>
34+
Parcelles {{ featureGroup.label.toLocaleLowerCase() }}
35+
</caption>
3336
<colgroup>
3437
<col class="selection" />
3538
<col class="labels" />
3639
<col class="certification" />
3740
<col class="surface" />
3841
<col class="actions" />
3942
</colgroup>
40-
<tr :hidden="!open" class="intermediate-header">
41-
<th scope="col"></th>
42-
<th scope="col" v-if="isGroupedByCulture">Nom</th>
43-
<th scope="col" v-else>Culture</th>
44-
<th scope="col" class="certification">
45-
<span class=" fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">Certification</span>
46-
</th>
47-
<th scope="col" class="surface">
48-
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">Surface</span>
49-
</th>
50-
<th scope="col" class="actions">Actions</th>
51-
</tr>
52-
<tr class="parcelle clickable" :class="{'parcelle--is-new': feature.id === Number(route.query?.new)}" :id="'parcelle-' + feature.id" :hidden="!open" v-for="feature in featureGroup.features" :key="feature.id" @mouseover="hoveredId = feature.id" :aria-current="feature.id === hoveredId ? 'location' : null">
53-
<th scope="row">
54-
<div class="fr-checkbox-group single-checkbox">
55-
<input type="checkbox" :id="'radio-' + feature.id" :checked="selectedIds.includes(feature.id)" @click="toggleSingleSelected(feature.id)" />
56-
<label class="fr-label" :for="'radio-' + feature.id" />
57-
</div>
58-
</th>
59-
<td @click="isOnline && toggleEditForm(feature.id)" v-if="isGroupedByCulture">
60-
<span class="culture-name">{{ featureName(feature) }}</span>
61-
<small class="feature-precision" v-if="feature.properties.cultures.length > 1">Multi-culture</small>
62-
<small class="feature-precision fr-hidden-sm fr-hidden-md fr-hidden-lg fr-hidden-xl">
63-
<ConversionLevel :feature="feature" with-date /><br />
64-
{{ inHa(legalProjectionSurface(feature)) }}&nbsp;ha
65-
</small>
66-
</td>
67-
<td @click="isOnline && toggleEditForm(feature.id)" v-else>
68-
<span class="culture-type" v-if="feature.properties.cultures.length > 1">
69-
Multi-cultures<span class="fr-sr-only"> : </span>
70-
<small class="feature-precision" v-for="(culture, i) in feature.properties.cultures" :key="i">
71-
<span v-if="i" class="fr-sr-only">, </span>{{ cultureLabel(culture) }}
43+
<tbody>
44+
<tr :hidden="!open" class="intermediate-header">
45+
<th scope="col" aria-hidden></th>
46+
<th scope="col" v-if="isGroupedByCulture">Nom</th>
47+
<th scope="col" v-else>Culture</th>
48+
<th scope="col" class="certification">
49+
<span class=" fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">Certification</span>
50+
</th>
51+
<th scope="col" class="surface">
52+
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">Surface</span>
53+
</th>
54+
<th scope="col" class="actions">Actions</th>
55+
</tr>
56+
<tr class="parcelle clickable" :class="{'parcelle--is-new': feature.id === Number(route.query?.new)}" :id="'parcelle-' + feature.id" :hidden="!open" v-for="feature in featureGroup.features" :key="feature.id" @mouseover="hoveredId = feature.id" :aria-current="feature.id === hoveredId ? 'location' : null">
57+
<th scope="row">
58+
<div class="fr-checkbox-group single-checkbox">
59+
<input type="checkbox" :id="'radio-' + feature.id" :checked="selectedIds.includes(feature.id)" @click="toggleSingleSelected(feature.id)" />
60+
<label class="fr-label" :for="'radio-' + feature.id" :aria-label="selectedIds.includes(feature.id) ? `Désélectionner ${featureName(feature)}` : `Sélectionner ${featureName(feature)}`" />
61+
</div>
62+
</th>
63+
<td @click="isOnline && toggleEditForm(feature.id)" v-if="isGroupedByCulture">
64+
<span class="culture-name">{{ featureName(feature) }}</span>
65+
<small class="feature-precision" v-if="feature.properties.cultures.length > 1">Multi-culture</small>
66+
<small class="feature-precision fr-hidden-sm fr-hidden-md fr-hidden-lg fr-hidden-xl">
67+
<ConversionLevel :feature="feature" with-date /><br />
68+
{{ inHa(legalProjectionSurface(feature)) }}&nbsp;ha
7269
</small>
73-
</span>
74-
<span class="culture-name" v-else>{{ cultureLabel(feature.properties.cultures[0]) }}</span>
75-
<small class="feature-precision">{{ featureName(feature) }}</small>
76-
</td>
77-
<td @click="isOnline && toggleEditForm(feature.id)">
78-
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">
79-
<ConversionLevel :feature="feature" with-date />
80-
</span>
81-
</td>
82-
<td @click="isOnline && toggleEditForm(feature.id)" class="numeric">
83-
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">
84-
{{ inHa(legalProjectionSurface(feature)) }}&nbsp;ha
85-
</span>
86-
</td>
87-
<td class="actions">
88-
<button
89-
type="button"
90-
class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl"
91-
:class="{'fr-btn': true, 'fr-btn--tertiary-no-outline': true, 'fr-icon-edit-line': true }"
92-
@click="toggleEditForm(feature.id)" aria-label="Modifier"
93-
/>
94-
95-
<ActionDropdown with-icons>
96-
<li v-if="permissions.canChangeGeometry && isOnline">
97-
<router-link :to="`/exploitations/${operatorStore.operator.numeroBio}/${recordStore.record.record_id}/modifier/${feature.id}`" type="button" class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
98-
Modifier le contour
99-
</router-link>
100-
</li>
101-
<li v-else>
102-
<button type="button" disabled class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
70+
</td>
71+
<td @click="isOnline && toggleEditForm(feature.id)" v-else>
72+
<span class="culture-type" v-if="feature.properties.cultures.length > 1">
73+
Multi-cultures<span class="fr-sr-only"> : </span>
74+
<small class="feature-precision" v-for="(culture, i) in feature.properties.cultures" :key="i">
75+
<span v-if="i" class="fr-sr-only">, </span>{{ cultureLabel(culture) }}
76+
</small>
77+
</span>
78+
<span class="culture-name" v-else>{{ cultureLabel(feature.properties.cultures[0]) }}</span>
79+
<small class="feature-precision">{{ featureName(feature) }}</small>
80+
</td>
81+
<td @click="isOnline && toggleEditForm(feature.id)">
82+
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">
83+
<ConversionLevel :feature="feature" with-date />
84+
</span>
85+
</td>
86+
<td @click="isOnline && toggleEditForm(feature.id)" class="numeric">
87+
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">
88+
{{ inHa(legalProjectionSurface(feature)) }}&nbsp;ha
89+
</span>
90+
</td>
91+
<td class="actions">
92+
<button
93+
type="button"
94+
class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl"
95+
:class="{'fr-btn': true, 'fr-btn--tertiary-no-outline': true, 'fr-icon-edit-line': true }"
96+
@click="toggleEditForm(feature.id)" aria-label="Modifier"
97+
/>
98+
99+
<ActionDropdown with-icons>
100+
<li v-if="permissions.canChangeGeometry && isOnline">
101+
<router-link :to="`/exploitations/${operatorStore.operator.numeroBio}/${recordStore.record.record_id}/modifier/${feature.id}`" type="button" class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
103102
Modifier le contour
104-
</button>
105-
</li>
106-
<li>
107-
<button
108-
type="button"
109-
@click.prevent="toggleDeleteForm(feature.id)"
110-
:disabled="!permissions.canDeleteFeature"
111-
class="fr-btn fr-btn--tertiary-no-outline fr-icon-delete-line btn--error fr-text--sm"
112-
>
113-
Supprimer la parcelle
114-
</button>
115-
</li>
116-
</ActionDropdown>
117-
</td>
118-
</tr>
103+
</router-link>
104+
</li>
105+
<li v-else>
106+
<button type="button" disabled class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
107+
Modifier le contour
108+
</button>
109+
</li>
110+
<li>
111+
<button
112+
type="button"
113+
@click.prevent="toggleDeleteForm(feature.id)"
114+
:disabled="!permissions.canDeleteFeature"
115+
class="fr-btn fr-btn--tertiary-no-outline fr-icon-delete-line btn--error fr-text--sm"
116+
>
117+
Supprimer la parcelle
118+
</button>
119+
</li>
120+
</ActionDropdown>
121+
</td>
122+
</tr>
123+
</tbody>
119124
</table>
125+
126+
<p :id="`operator-features-summary-${featureGroup.key}`" class="fr-sr-only">
127+
Liste de {{ featureGroup.features.length }} parcelles cultivées en {{ featureGroup.label.toLocaleLowerCase() }}.
128+
La première colonne contient le nom de la parcelle ;
129+
la seconde, son statut de certification et éventuelle date de début de conversion ;
130+
la troisième, sa surface en hectares ;
131+
la quatrième et dernière colonne, des boutons d'action.
132+
</p>
120133
</td>
121134
</tr>
122135
</tbody>
@@ -209,6 +222,8 @@ watch(selectedIds, (selectedIds, prevSelectedIds) => {
209222
--hover: transparent;
210223
--active: transparent;
211224
225+
padding-left: 0;
226+
padding-right: 0; /* to text align buttons/texts in this column, and because actions are already padded */
212227
position: relative;
213228
text-align: left;
214229
white-space: nowrap;

src/components/records/Table/index.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe("Features Table", () => {
3737
const wrapper = mount(TableComponent)
3838

3939
expect(wrapper.find('tr.summary td:nth-child(2)').text()).toContain("4 parcelles")
40-
expect(wrapper.findAll('table tbody')).toHaveLength(3)
40+
expect(wrapper.findAll('table.group-table tbody')).toHaveLength(3)
4141
expect(wrapper.find('#parcelle-1').attributes()).toHaveProperty('hidden', '')
4242
})
4343

@@ -86,7 +86,7 @@ describe("Features Table", () => {
8686

8787
// await rendering
8888
await flushPromises()
89-
const groups = wrapper.findAll('table tbody')
89+
const groups = wrapper.findAll('tbody.feature-group')
9090

9191
expect(groups.at(0).find('th[scope="row"]').text()).toContain('26108')
9292
expect(groups.at(1).find('th[scope="row"]').text()).toContain('26113')

src/components/records/Table/index.vue

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
</li>
1010
</ul>
1111

12-
<table @mouseout="hoveredFeatureId = null" id="parcellaire-table">
13-
<caption>Parcellaire agricole</caption>
12+
<table @mouseout="hoveredFeatureId = null" id="parcellaire-table" aria-describedby="operator-features-summary-global">
13+
<caption>
14+
Parcelles agricoles {{ record.version_name }} de l'opérateur {{ operator.nom }}
15+
</caption>
1416
<colgroup>
1517
<col class="selection" />
1618
<col class="accordion" />
@@ -37,13 +39,13 @@
3739
<th colspan="2">
3840
<div class="fr-checkbox-group single-checkbox" v-if="hasFeatures">
3941
<input type="checkbox" id="radio-select-all" :checked="allSelected" @click="toggleAllSelected" />
40-
<label class="fr-label" for="radio-select-all" />
42+
<label class="fr-label" for="radio-select-all" :aria-label="allSelected ? 'Tout désélectionner' : 'Tout sélectionner'" />
4143
</div>
4244
</th>
4345
<th class="labels" scope="col">
4446
<div class="seamless-select">
4547
<label for="plots-group-by">Parcelles par </label>
46-
<b>{{ groupingChoices[userGroupingChoice].label }}</b>
48+
<b>{{ groupingChoiceLabel }}</b>
4749
<select id="plots-group-by" v-model="userGroupingChoice">
4850
<option :value="key" v-for="({ label }, key) in groupingChoices" :key="key">
4951
{{ label }}
@@ -82,10 +84,19 @@
8284
</td>
8385
</tr>
8486
</tbody>
85-
86-
<FeatureGroup v-for="featureGroup in featureGroups" :featureGroup="featureGroup" :key="featureGroup.key" @edit:featureId="(featuredId) => editedFeatureId = featuredId" @delete:featureId="(featureId) => maybeDeletedFeatureId = featureId" />
87+
<tbody v-else>
88+
<FeatureGroup v-for="featureGroup in featureGroups" :featureGroup="featureGroup" :key="featureGroup.key" @edit:featureId="(featuredId) => editedFeatureId = featuredId" @delete:featureId="(featureId) => maybeDeletedFeatureId = featureId" />
89+
</tbody>
8790
</table>
8891

92+
<p id="operator-features-summary-global" class="fr-sr-only" v-if="hasFeatures">
93+
Liste de {{ features.length }} parcelles regroupées par {{ groupingChoiceLabel }}.
94+
Actuellement, {{ selectedFeatureIds.length }} parcelles sont sélectionnées.
95+
</p>
96+
<p id="operator-features-summary-global" class="fr-sr-only" v-else>
97+
Ce parcellaire ne contient aucune parcelle.
98+
</p>
99+
89100
<p class="fr-my-3w" v-if="permissions.canAddParcelle && isOnline">
90101
<router-link :to="`/exploitations/${operator.numeroBio}/${record.record_id}/ajout-parcelle`" class="fr-btn fr-btn--secondary fr-icon--sm fr-btn--icon-left fr-icon-add-line">Ajouter une parcelle</router-link>
91102
</p>
@@ -155,6 +166,7 @@ const maybeDeletedFeatureId = ref(null)
155166
156167
const userGroupingChoice = ref('CULTURE')
157168
const featureGroups = computed(() => getFeatureGroups({ features: features.value }, userGroupingChoice.value))
169+
const groupingChoiceLabel = computed(() => groupingChoices[userGroupingChoice.value].label)
158170
159171
async function handleSingleFeatureSubmit ({ id, properties }) {
160172
statsPush(['trackEvent', 'Parcelles', 'Modification individuelle (sauvegarde)'])
@@ -276,6 +288,13 @@ function handleFilterClick (id) {
276288
background-image: linear-gradient(0deg, var(--border-active-blue-france), var(--border-active-blue-france)), linear-gradient(0deg, var(--border-active-blue-france), var(--border-active-blue-france));
277289
}
278290
291+
.fr-table thead,
292+
.fr-table .summary {
293+
td, th {
294+
padding-left: 0.6rem;
295+
}
296+
}
297+
279298
.fr-table .summary.summary__mass-actions {
280299
color: var(--text-inverted-blue-france);
281300
background-color: var(--background-action-high-blue-france);

src/components/widgets/TableSort.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<slot name="default" />
44
</label>
55

6-
<button v-if="showControl" type="button" :aria-pressed="isAscending || isDescending" :id="id" class="fr-btn fr-btn--tertiary-no-outline" @click="emit('update:modelValue', { sort: code, order: !isAscending ? 'asc' : 'desc' })">
6+
<button v-if="showControl" type="button" :aria-pressed="isAscending || isDescending" :id="id" class="fr-btn fr-btn--tertiary-no-outline" @click="emit('update:modelValue', { sort: code, order: !isAscending ? 'asc' : 'desc' })" :aria-label="`Trier par ${$slots.default()[0].children.toLocaleLowerCase()}`">
77
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
88
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 0L13 6H1L7 0Z" :fill="isAscending ? '#000091' : '#929292'"/>
99
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 16L1 10L13 10L7 16Z" :fill="isDescending ? '#000091' : '#929292'"/>

src/pages/certification/exploitations/index.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ meta:
4646

4747
<Conflict v-if="storage.conflicts.size" />
4848

49-
<div class="fr-table fr-table--bordered">
50-
<table>
49+
<div class="fr-table fr-table--bordered fr-table--no-caption">
50+
<table aria-describedby="operator-summary-global">
51+
<caption>
52+
Opérateurs {{ user.organismeCertificateur.nom }}
53+
</caption>
5154
<colgroup>
5255
<col width="45%" />
5356
<col width="15%" />
@@ -132,6 +135,14 @@ meta:
132135
</tfoot>
133136
</table>
134137

138+
<p id="operators-summary-global" class="fr-sr-only">
139+
Liste paginée des versions les plus récentes de parcellaires de {{ pagination.total }} opérateurs.
140+
La première colonne contient le nom de l'opérateur ;
141+
la seconde, la date de début de conversion (si applicable) ;
142+
la troisième, la date d'audit ;
143+
la quatrième et dernière colonne, le statut de certification.
144+
</p>
145+
135146
<p class="fr-mt-3w">
136147
<span class="fr-icon fr-icon-questionnaire-fill fr-mr-1w" aria-hidden />
137148

0 commit comments

Comments
 (0)