mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
A11Y: improve topic list table markup for screenreaders (#27808)
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
This commit is contained in:
parent
aedff155bd
commit
0e3ed7ea2a
@ -1,3 +1,5 @@
|
|||||||
|
<caption class="sr-only">{{i18n "sr_topic_list_caption"}}</caption>
|
||||||
|
|
||||||
<thead class="topic-list-header">
|
<thead class="topic-list-header">
|
||||||
{{raw
|
{{raw
|
||||||
"topic-list-header"
|
"topic-list-header"
|
||||||
|
@ -101,6 +101,7 @@ export default class TopicList extends Component {
|
|||||||
(if this.bulkSelectEnabled "sticky-header")
|
(if this.bulkSelectEnabled "sticky-header")
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<caption class="sr-only">{{i18n "sr_topic_list_caption"}}</caption>
|
||||||
<thead class="topic-list-header">
|
<thead class="topic-list-header">
|
||||||
<TopicListHeader
|
<TopicListHeader
|
||||||
@canBulkSelect={{@canBulkSelect}}
|
@canBulkSelect={{@canBulkSelect}}
|
||||||
|
@ -66,6 +66,7 @@ export default class TopicEntrance extends Component {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DMenu
|
<DMenu
|
||||||
|
@title={{@title}}
|
||||||
@ariaLabel={{@title}}
|
@ariaLabel={{@title}}
|
||||||
@placement="center"
|
@placement="center"
|
||||||
@autofocus={{true}}
|
@autofocus={{true}}
|
||||||
|
@ -83,9 +83,6 @@ export default class TopicListHeaderColumn extends Component {
|
|||||||
{{(if @sortable (modifier on "keydown" this.onKeyDown))}}
|
{{(if @sortable (modifier on "keydown" this.onKeyDown))}}
|
||||||
data-sort-order={{@order}}
|
data-sort-order={{@order}}
|
||||||
scope="col"
|
scope="col"
|
||||||
tabindex={{if @sortable "0"}}
|
|
||||||
role={{if @sortable "button"}}
|
|
||||||
aria-pressed={{this.isSorting}}
|
|
||||||
aria-sort={{this.ariaSort}}
|
aria-sort={{this.ariaSort}}
|
||||||
class={{concatClass
|
class={{concatClass
|
||||||
"topic-list-data"
|
"topic-list-data"
|
||||||
@ -144,7 +141,14 @@ export default class TopicListHeaderColumn extends Component {
|
|||||||
@changeNewListSubset={{@changeNewListSubset}}
|
@changeNewListSubset={{@changeNewListSubset}}
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span>{{this.localizedName}}</span>
|
<span
|
||||||
|
class={{if @screenreaderOnly "sr-only"}}
|
||||||
|
tabindex={{if @sortable "0"}}
|
||||||
|
role={{if @sortable "button"}}
|
||||||
|
aria-pressed={{this.isSorting}}
|
||||||
|
>
|
||||||
|
{{this.localizedName}}
|
||||||
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ const TopicListHeader = <template>
|
|||||||
@activeOrder={{@order}}
|
@activeOrder={{@order}}
|
||||||
@changeSort={{@changeSort}}
|
@changeSort={{@changeSort}}
|
||||||
@ascending={{@ascending}}
|
@ascending={{@ascending}}
|
||||||
|
@name="posters"
|
||||||
|
@screenreaderOnly={{true}}
|
||||||
aria-label={{i18n "category.sort_options.posters"}}
|
aria-label={{i18n "category.sort_options.posters"}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@ -62,7 +64,6 @@ const TopicListHeader = <template>
|
|||||||
@changeSort={{@changeSort}}
|
@changeSort={{@changeSort}}
|
||||||
@ascending={{@ascending}}
|
@ascending={{@ascending}}
|
||||||
@name="replies"
|
@name="replies"
|
||||||
aria-label={{i18n "sr_replies"}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{{#if @showLikes}}
|
{{#if @showLikes}}
|
||||||
@ -74,7 +75,6 @@ const TopicListHeader = <template>
|
|||||||
@changeSort={{@changeSort}}
|
@changeSort={{@changeSort}}
|
||||||
@ascending={{@ascending}}
|
@ascending={{@ascending}}
|
||||||
@name="likes"
|
@name="likes"
|
||||||
aria-label={{i18n "sr_likes"}}
|
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
@ -87,7 +87,6 @@ const TopicListHeader = <template>
|
|||||||
@changeSort={{@changeSort}}
|
@changeSort={{@changeSort}}
|
||||||
@ascending={{@ascending}}
|
@ascending={{@ascending}}
|
||||||
@name="likes"
|
@name="likes"
|
||||||
aria-label={{i18n "sr_op_likes"}}
|
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
@ -99,7 +98,6 @@ const TopicListHeader = <template>
|
|||||||
@changeSort={{@changeSort}}
|
@changeSort={{@changeSort}}
|
||||||
@ascending={{@ascending}}
|
@ascending={{@ascending}}
|
||||||
@name="views"
|
@name="views"
|
||||||
aria-label={{i18n "sr_views"}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TopicListHeaderColumn
|
<TopicListHeaderColumn
|
||||||
@ -110,7 +108,6 @@ const TopicListHeader = <template>
|
|||||||
@changeSort={{@changeSort}}
|
@changeSort={{@changeSort}}
|
||||||
@ascending={{@ascending}}
|
@ascending={{@ascending}}
|
||||||
@name="activity"
|
@name="activity"
|
||||||
aria-label={{i18n "sr_activity"}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PluginOutlet @name="topic-list-header-after" />
|
<PluginOutlet @name="topic-list-header-after" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<{{view.tagName}} class='num posts-map posts {{view.likesHeat}} topic-list-data' title='{{view.title}}'>
|
<{{view.tagName}} class='num posts-map posts {{view.likesHeat}} topic-list-data'>
|
||||||
<button class="btn-link posts-map badge-posts {{view.likesHeat}}" aria-label="{{view.title}}">
|
<button class="btn-link posts-map badge-posts {{view.likesHeat}}" title="{{view.title}}" aria-label="{{view.title}}">
|
||||||
{{raw-plugin-outlet name="topic-list-before-reply-count"}}
|
{{raw-plugin-outlet name="topic-list-before-reply-count"}}
|
||||||
{{number topic.replyCount noTitle="true"}}
|
{{number topic.replyCount noTitle="true"}}
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<th data-sort-order='{{order}}' class='{{view.className}} topic-list-data' scope="col" {{#if ariaLabel}}aria-label='{{ariaLabel}}'{{/if}} {{#if sortable}}tabindex="0" role="button" aria-pressed='{{view.ariaPressed}}' {{#if view.ariaSort}}aria-sort='{{view.ariaSort}}'{{/if}} {{/if}}>
|
<th data-sort-order='{{order}}' class='{{view.className}} topic-list-data' scope="col" {{#if view.ariaSort}}aria-sort='{{view.ariaSort}}'{{/if}}>
|
||||||
{{~#if canBulkSelect}}
|
{{~#if canBulkSelect}}
|
||||||
{{~#if showBulkToggle}}
|
{{~#if showBulkToggle}}
|
||||||
{{~#if experimentalTopicBulkActionsEnabled }}
|
{{~#if experimentalTopicBulkActionsEnabled }}
|
||||||
@ -25,7 +25,7 @@
|
|||||||
{{~#if view.showTopicsAndRepliesToggle}}
|
{{~#if view.showTopicsAndRepliesToggle}}
|
||||||
{{raw "list/new-list-header-controls" current=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount}}
|
{{raw "list/new-list-header-controls" current=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span>{{view.localizedName}}</span>
|
<span {{#if view.screenreaderOnly}}class="sr-only"{{/if}} {{#if sortable}}tabindex="0" role="button" aria-pressed='{{view.ariaPressed}}'{{/if}}>{{view.localizedName}}</span>
|
||||||
{{/if ~}}
|
{{/if ~}}
|
||||||
{{/unless ~}}
|
{{/unless ~}}
|
||||||
{{~#if view.isSorting}}
|
{{~#if view.isSorting}}
|
||||||
|
@ -13,15 +13,15 @@
|
|||||||
{{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions showTopicsAndRepliesToggle=showTopicsAndRepliesToggle newListSubset=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount experimentalTopicBulkActionsEnabled=experimentalTopicBulkActionsEnabled bulkSelectHelper=bulkSelectHelper }}
|
{{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions showTopicsAndRepliesToggle=showTopicsAndRepliesToggle newListSubset=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount experimentalTopicBulkActionsEnabled=experimentalTopicBulkActionsEnabled bulkSelectHelper=bulkSelectHelper }}
|
||||||
{{raw-plugin-outlet name="topic-list-header-after-main-link"}}
|
{{raw-plugin-outlet name="topic-list-header-after-main-link"}}
|
||||||
{{#if showPosters}}
|
{{#if showPosters}}
|
||||||
{{raw "topic-list-header-column" order='posters' ariaLabel=(i18n "category.sort_options.posters")}}
|
{{raw "topic-list-header-column" name='posters' screenreaderOnly='true'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{raw "topic-list-header-column" sortable=sortable number='true' order='posts' name='replies' ariaLabel=(i18n "sr_replies")}}
|
{{raw "topic-list-header-column" sortable=sortable number='true' order='posts' name='replies'}}
|
||||||
{{#if showLikes}}
|
{{#if showLikes}}
|
||||||
{{raw "topic-list-header-column" sortable=sortable number='true' order='likes' name='likes' ariaLabel=(i18n "sr_likes")}}
|
{{raw "topic-list-header-column" sortable=sortable number='true' order='likes' name='likes'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if showOpLikes}}
|
{{#if showOpLikes}}
|
||||||
{{raw "topic-list-header-column" sortable=sortable number='true' order='op_likes' name='likes' ariaLabel=(i18n "sr_op_likes")}}
|
{{raw "topic-list-header-column" sortable=sortable number='true' order='op_likes' name='likes'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{raw "topic-list-header-column" sortable=sortable number='true' order='views' name='views' ariaLabel=(i18n "sr_views")}}
|
{{raw "topic-list-header-column" sortable=sortable number='true' order='views' name='views'}}
|
||||||
{{raw "topic-list-header-column" sortable=sortable number='true' order='activity' name='activity' ariaLabel=(i18n "sr_activity")}}
|
{{raw "topic-list-header-column" sortable=sortable number='true' order='activity' name='activity'}}
|
||||||
{{~raw-plugin-outlet name="topic-list-header-after"~}}
|
{{~raw-plugin-outlet name="topic-list-header-after"~}}
|
||||||
|
@ -19,7 +19,10 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
@discourseComputed("topic.replyCount", "ratioText")
|
@discourseComputed("topic.replyCount", "ratioText")
|
||||||
title(count, ratio) {
|
title(count, ratio) {
|
||||||
return I18n.messageFormat("posts_likes_MF", { count, ratio }).trim();
|
return I18n.messageFormat("posts_likes_MF", {
|
||||||
|
count,
|
||||||
|
ratio,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("ratio")
|
@discourseComputed("ratio")
|
||||||
|
@ -4141,36 +4141,33 @@ en:
|
|||||||
pending_posts:
|
pending_posts:
|
||||||
label: "Pending"
|
label: "Pending"
|
||||||
label_with_count: "Pending (%{count})"
|
label_with_count: "Pending (%{count})"
|
||||||
|
sr_topic_list_caption: Topic list, column headers with buttons are sortable.
|
||||||
|
|
||||||
# This string uses the ICU Message Format. See https://meta.discourse.org/t/7035 for translation guidelines.
|
# This string uses the ICU Message Format. See https://meta.discourse.org/t/7035 for translation guidelines.
|
||||||
posts_likes_MF: |
|
posts_likes_MF: |
|
||||||
This topic has { count, plural,
|
{ count, plural,
|
||||||
one {# reply}
|
one {# reply,}
|
||||||
other {# replies}
|
other {# replies,}
|
||||||
}{ ratio, select,
|
}{ ratio, select,
|
||||||
low {with a high like to post ratio}
|
low { high like to post ratio,}
|
||||||
med {with a very high like to post ratio}
|
med { very high like to post ratio,}
|
||||||
high {with an extremely high like to post ratio}
|
high { extremely high like to post ratio,}
|
||||||
other {}
|
other {}
|
||||||
}
|
} jump to the first or last post…
|
||||||
|
|
||||||
|
posters: "Posters"
|
||||||
latest_poster_link: "%{username}'s profile, latest poster"
|
latest_poster_link: "%{username}'s profile, latest poster"
|
||||||
original_post: "Original Post"
|
original_post: "Original Post"
|
||||||
views: "Views"
|
views: "Views"
|
||||||
sr_views: "Sort by views"
|
|
||||||
views_lowercase:
|
views_lowercase:
|
||||||
one: "view"
|
one: "view"
|
||||||
other: "views"
|
other: "views"
|
||||||
replies: "Replies"
|
replies: "Replies"
|
||||||
sr_replies: "Sort by replies"
|
|
||||||
views_long:
|
views_long:
|
||||||
one: "this topic has been viewed %{count} time"
|
one: "this topic has been viewed %{count} time"
|
||||||
other: "this topic has been viewed %{count} times"
|
other: "this topic has been viewed %{count} times"
|
||||||
activity: "Activity"
|
activity: "Activity"
|
||||||
sr_activity: "Sort by activity"
|
|
||||||
likes: "Likes"
|
likes: "Likes"
|
||||||
sr_likes: "Sort by likes"
|
|
||||||
sr_op_likes: "Sort by original post likes"
|
|
||||||
likes_lowercase:
|
likes_lowercase:
|
||||||
one: "like"
|
one: "like"
|
||||||
other: "likes"
|
other: "likes"
|
||||||
|
@ -172,7 +172,7 @@ RSpec.describe JsLocaleHelper do
|
|||||||
it "translates messages properly" do
|
it "translates messages properly" do
|
||||||
expect(
|
expect(
|
||||||
translated_message,
|
translated_message,
|
||||||
).to eq "This topic has 3 replies with a very high like to post ratio\n"
|
).to eq "3 replies, very high like to post ratio, jump to the first or last post…\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the translation is overriden" do
|
context "when the translation is overriden" do
|
||||||
@ -207,7 +207,7 @@ RSpec.describe JsLocaleHelper do
|
|||||||
it "returns the fallback translation" do
|
it "returns the fallback translation" do
|
||||||
expect(
|
expect(
|
||||||
translated_message,
|
translated_message,
|
||||||
).to eq "This topic has 3 replies with a very high like to post ratio\n"
|
).to eq "3 replies, very high like to post ratio, jump to the first or last post…\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the fallback translation is overriden" do
|
context "when the fallback translation is overriden" do
|
||||||
|
Loading…
Reference in New Issue
Block a user