diff --git a/app/assets/javascripts/discourse/app/widgets/actions-summary.js b/app/assets/javascripts/discourse/app/widgets/actions-summary.js index 16f6be54edd..73c8a88ad2d 100644 --- a/app/assets/javascripts/discourse/app/widgets/actions-summary.js +++ b/app/assets/javascripts/discourse/app/widgets/actions-summary.js @@ -23,6 +23,14 @@ createWidget("small-user-list", { return atts.listClassName; }, + buildAttributes(attrs) { + const attributes = { role: "list" }; + if (attrs.ariaLabel) { + attributes["aria-label"] = attrs.ariaLabel; + } + return attributes; + }, + html(atts) { let users = atts.users; if (users) { @@ -37,7 +45,11 @@ createWidget("small-user-list", { let description = null; if (atts.description) { - description = I18n.t(atts.description, { count: atts.count }); + description = h( + "span", + { attributes: { "aria-hidden": true } }, + I18n.t(atts.description, { count: atts.count }) + ); } // oddly post_url is on the user @@ -46,10 +58,16 @@ createWidget("small-user-list", { postUrl = postUrl || u.post_url; if (u.unknown) { return h("div.unknown", { - attributes: { title: I18n.t("post.unknown_user") }, + attributes: { + title: I18n.t("post.unknown_user"), + role: "listitem", + }, }); } else { - return avatarFor.call(this, "small", u); + return avatarFor.call(this, "small", u, { + role: "listitem", + "aria-hidden": false, + }); } }); diff --git a/app/assets/javascripts/discourse/app/widgets/button.js b/app/assets/javascripts/discourse/app/widgets/button.js index 242736aec1c..acedbd34083 100644 --- a/app/assets/javascripts/discourse/app/widgets/button.js +++ b/app/assets/javascripts/discourse/app/widgets/button.js @@ -45,6 +45,14 @@ export const ButtonClass = { attributes["role"] = attrs.role; } + if (attrs.translatedAriaLabel) { + attributes["aria-label"] = attrs.translatedAriaLabel; + } + + if (attrs.ariaPressed) { + attributes["aria-pressed"] = attrs.ariaPressed; + } + if (attrs.tabAttrs) { const tab = attrs.tabAttrs; attributes["aria-selected"] = tab["aria-selected"]; diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js index a9187ff9f50..ee5a4173114 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js @@ -5,6 +5,7 @@ import { formattedReminderTime } from "discourse/lib/bookmark"; import { h } from "virtual-dom"; import showModal from "discourse/lib/show-modal"; import { smallUserAtts } from "discourse/widgets/actions-summary"; +import I18n from "I18n"; const LIKE_ACTION = 2; const VIBRATE_DURATION = 5; @@ -64,10 +65,14 @@ export function buildButton(name, widget) { } } -registerButton("read-count", (attrs) => { +registerButton("read-count", (attrs, state) => { if (attrs.showReadIndicator) { const count = attrs.readCount; if (count > 0) { + let ariaPressed = "false"; + if (state?.readers && state.readers.length > 0) { + ariaPressed = "true"; + } return { action: "toggleWhoRead", title: "post.controls.read_indicator", @@ -75,6 +80,10 @@ registerButton("read-count", (attrs) => { contents: count, iconRight: true, addContainer: false, + translatedAriaLabel: I18n.t("post.sr_post_read_count_button", { + count, + }), + ariaPressed, }; } } @@ -93,7 +102,7 @@ registerButton("read", (attrs) => { } }); -function likeCount(attrs) { +function likeCount(attrs, state) { const count = attrs.likeCount; if (count > 0) { @@ -111,6 +120,10 @@ function likeCount(attrs) { addContainer = true; } + let ariaPressed = "false"; + if (state?.likedUsers && state.likedUsers.length > 0) { + ariaPressed = "true"; + } return { action: "toggleWhoLiked", title, @@ -120,6 +133,8 @@ function likeCount(attrs) { iconRight: true, addContainer, titleOptions: { count: attrs.liked ? count - 1 : count }, + translatedAriaLabel: I18n.t("post.sr_post_like_count_button", { count }), + ariaPressed, }; } } @@ -630,6 +645,9 @@ export default createWidget("post-menu", { listClassName: "who-read", description, count, + ariaLabel: I18n.t( + "post.actions.people.sr_post_readers_list_description" + ), }) ); } @@ -649,6 +667,9 @@ export default createWidget("post-menu", { listClassName: "who-liked", description, count, + ariaLabel: I18n.t( + "post.actions.people.sr_post_likers_list_description" + ), }) ); } diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js index ca5beb554fe..0e014710250 100644 --- a/app/assets/javascripts/discourse/app/widgets/post.js +++ b/app/assets/javascripts/discourse/app/widgets/post.js @@ -68,16 +68,20 @@ export function avatarImg(wanted, attrs) { return h("img", properties); } -export function avatarFor(wanted, attrs) { +export function avatarFor(wanted, attrs, linkAttrs) { + const attributes = { + href: attrs.url, + "data-user-card": attrs.username, + "aria-hidden": true, + }; + if (linkAttrs) { + Object.assign(attributes, linkAttrs); + } return h( "a", { className: `trigger-user-card ${attrs.className || ""}`, - attributes: { - href: attrs.url, - "data-user-card": attrs.username, - "aria-hidden": true, - }, + attributes, }, avatarImg(wanted, attrs) ); diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 8655fc83fdf..eef8d919fe6 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3091,6 +3091,12 @@ en: one: "you and %{count} other person liked this post" other: "you and %{count} other people liked this post" + sr_post_like_count_button: + one: "%{count} person liked this post. Click to view" + other: "%{count} people liked this post. Click to view" + sr_post_read_count_button: + one: "%{count} person read this post. Click to view" + other: "%{count} people read this post. Click to view" filtered_replies_hint: one: "View this post and its reply" other: "View this post and its %{count} replies" @@ -3201,6 +3207,8 @@ en: read_capped: one: "and %{count} other read this" other: "and %{count} others read this" + sr_post_likers_list_description: "users who liked this post" + sr_post_readers_list_description: "users who read this post" by_you: off_topic: "You flagged this as off-topic" spam: "You flagged this as spam"