A11Y: multiple fixes to user stream items (#18368)

- in group activity, allows avatars to be selectable by tabbing or screen readers
- in user activity > drafts, fixes a bug where for draft replies, the wrong avatar was being shown in the user card
- in both group and user activity, fixes the order of focusable items
This commit is contained in:
Penar Musaraj 2022-09-27 10:59:26 -04:00 committed by GitHub
parent b97cb222c2
commit 217274f2c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 71 additions and 39 deletions

View File

@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators";
import getURL from "discourse-common/lib/get-url";
import { prioritizeNameInUx } from "discourse/lib/settings";
import { propertyEqual } from "discourse/lib/computed";
import { userPath } from "discourse/lib/url";
export default Component.extend({
classNameBindings: [
@ -35,4 +36,9 @@ export default Component.extend({
return `group-${postUser.primary_group_name}`;
}
},
@discourseComputed("post.user.username")
userUrl(username) {
return userPath(username.toLowerCase());
},
});

View File

@ -2,6 +2,8 @@ import Component from "@ember/component";
import { actionDescription } from "discourse/widgets/post-small-action";
import { computed } from "@ember/object";
import { propertyEqual } from "discourse/lib/computed";
import { userPath } from "discourse/lib/url";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "li",
@ -28,4 +30,9 @@ export default Component.extend({
"item.created_at",
"item.action_code_who"
),
@discourseComputed("item.draft_username", "item.username")
userUrl(draftUsername, username) {
return userPath((draftUsername || username).toLowerCase());
},
});

View File

@ -1,4 +1,4 @@
import { and, equal, or } from "@ember/object/computed";
import { equal, or } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import categoryFromId from "discourse-common/utils/category-macro";
import RestModel from "discourse/models/rest";
@ -108,7 +108,6 @@ const UserAction = RestModel.extend({
mentionType: equal("action_type", UserActionTypes.mentions),
isPM: or("messageSentType", "messageReceivedType"),
postReplyType: or("postType", "replyType"),
removableBookmark: and("bookmarkType", "sameUser"),
addChild(action) {
let groups = this.childGroups;

View File

@ -1,11 +1,9 @@
<div class="clearfix info">
<a href={{this.post.user.userUrl}} data-user-card={{this.post.user.username}} class="avatar-link">
<div class="user-stream-item__header info">
<a href={{this.userUrl}} data-user-card={{this.post.user.username}} class="avatar-link">
{{avatar this.post.user imageSize="large" extraClasses="actor" ignoreTitle="true"}}
</a>
<span class="time">{{format-date this.post.created_at leaveAgo="true"}}</span>
<ExpandPost @item={{this.post}} />
<div class="stream-topic-details">
<div class="user-stream-item__details">
<div class="stream-topic-title">
<span class="title">
<a href={{this.postUrl}}>{{html-safe this.post.topic.fancyTitle}}</a>
@ -20,6 +18,9 @@
</div>
{{/if}}
</div>
<ExpandPost @item={{this.post}} />
<span class="time">{{format-date this.post.created_at leaveAgo="true"}}</span>
</div>
<div class="excerpt">

View File

@ -1,12 +1,11 @@
<div class="clearfix info">
<a href={{@item.userUrl}} data-user-card={{@item.username}} class="avatar-link"><div class="avatar-wrapper">{{avatar @item imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div></a>
<span class="time">{{format-date @item.created_at}}</span>
{{#if @item.draftType}}
<span class="draft-type">{{html-safe @item.draftType}}</span>
{{else}}
<ExpandPost @item={{@item}} />
{{/if}}
<div class="stream-topic-details">
<div class="user-stream-item__header info">
<a href={{this.userUrl}} data-user-card={{(or @item.draft_username @item.username)}} class="avatar-link">
<div class="avatar-wrapper">
{{avatar @item imageSize="large" extraClasses="actor" ignoreTitle="true"}}
</div>
</a>
<div class="user-stream-item__details">
<div class="stream-topic-title">
<TopicStatus @topic={{@item}} @disableActions={{true}} />
<span class="title">
@ -20,6 +19,13 @@
<div class="category">{{category-link @item.category}}</div>
</div>
{{#if @item.draftType}}
<span class="draft-type">{{html-safe @item.draftType}}</span>
{{else}}
<ExpandPost @item={{@item}} />
{{/if}}
<span class="time">{{format-date @item.created_at}}</span>
{{#if @item.deleted_by}}
<span class="delete-info">
{{d-icon "far-trash-alt"}}
@ -50,12 +56,12 @@
<div class="user-stream-item-actions child-actions">
{{d-icon child.icon class="icon"}}
{{#each child.items as |grandChild|}}
{{#if grandChild.removableBookmark}}
<DButton @class="btn-default remove-bookmark" @action={{action @removeBookmark grandChild}} @icon="times" @label="bookmarks.remove" />
{{else}}
<a href={{grandChild.userUrl}} data-user-card={{grandChild.username}} class="avatar-link"><div class="avatar-wrapper">{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true" avatarTemplatePath="acting_avatar_template"}}</div></a>
<a href={{grandChild.userUrl}} data-user-card={{grandChild.username}} class="avatar-link">
<div class="avatar-wrapper">
{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true" avatarTemplatePath="acting_avatar_template"}}
</div>
</a>
{{#if grandChild.edit_reason}} &mdash; <span class="edit-reason">{{grandChild.edit_reason}}</span>{{/if}}
{{/if}}
{{/each}}
</div>
{{/each}}

View File

@ -283,6 +283,13 @@ acceptance("Group - Authenticated", function (needs) {
);
await click(".dialog-footer .btn-default");
await visit("/g/discourse/activity/posts");
assert.ok(
".user-stream-item a.avatar-link[href='/u/awesomerobot']",
"avatar link contains href (is tabbable)"
);
});
test("Moderator Viewing Group", async function (assert) {

View File

@ -62,5 +62,12 @@ acceptance("User Drafts", function (needs) {
),
"shows the excerpt"
);
assert.ok(
query(".user-stream-item:nth-child(2) a.avatar-link").href.endsWith(
"/u/eviltrout"
),
"has correct avatar link"
);
});
});

View File

@ -26,7 +26,7 @@ export default {
draft_key: "topic_280",
sequence: 0,
draft_username: "eviltrout",
avatar_template: "/letter_avatar_proxy/v2/letter/p/a87d85/{size}.png",
avatar_template: "/user_avatar/localhost/eviltrout/{size}/2_1.png",
data: '{"reply":"The last reply to this topic was 6 months ago. Your reply will bump the topic to the top of its list.","action":"reply","categoryId":8,"archetypeId":"regular","metaData":null,"composerTime":139499,"typingTime":6100}',
topic_id: 280,
username: "zogstrip",

View File

@ -26,6 +26,15 @@
}
}
.user-stream-item__header {
display: flex;
align-items: flex-start;
}
.user-stream-item__details {
flex-grow: 1;
}
.type,
span.name {
color: var(--primary);
@ -34,9 +43,10 @@
.time,
.delete-info,
.draft-type {
float: right;
line-height: var(--line-height-small);
color: var(--primary-medium);
font-size: $font-down-2;
padding-top: 5px;
}
.notification .time {
@ -44,30 +54,21 @@
float: none;
}
.draft-type {
clear: right;
}
.delete-info .d-icon {
font-size: $font-0;
}
.expand-item,
.collapse-item {
float: right;
margin-right: 0.5em;
line-height: $line-height-small;
margin-left: 0.25em;
line-height: var(--line-height-small);
padding-top: 3px;
color: var(--primary-medium);
}
.avatar-link {
float: left;
margin-right: 4px;
}
.title {
@include ellipsis;
display: block;
margin-right: 0.5em;
}
.name {
@ -81,10 +82,8 @@
padding: 3px 5px 5px 5px;
}
.remove-bookmark,
.remove-draft {
float: right;
margin-top: -4px;
}
.notification {