A11Y: fix setting focus to a post (#23367)

This is a second attempt to fix this issue. First fix at #23243, see PR for details.
This commit is contained in:
Penar Musaraj 2023-12-07 15:44:42 -05:00 committed by GitHub
parent 290f6a70bd
commit 9dce1592dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 52 additions and 47 deletions

View File

@ -10,9 +10,7 @@ import DiscourseURL from "discourse/lib/url";
import Composer from "discourse/models/composer";
import { capabilities } from "discourse/services/capabilities";
import { INPUT_DELAY } from "discourse-common/config/environment";
import discourseDebounce from "discourse-common/lib/debounce";
import discourseLater from "discourse-common/lib/later";
import { bind } from "discourse-common/utils/decorators";
import domUtils from "discourse-common/utils/dom-utils";
let extraKeyboardShortcutsHelp = {};
@ -750,8 +748,11 @@ export default {
for (const a of articles) {
a.classList.remove("selected");
a.removeAttribute("tabindex");
}
article.classList.add("selected");
article.setAttribute("tabindex", "0");
article.focus();
this.appEvents.trigger("keyboard:move-selection", {
articles,
@ -768,8 +769,7 @@ export default {
);
} else if (article.classList.contains("topic-post")) {
return this._scrollTo(
article.querySelector("#post_1") ? 0 : articleTopPosition,
{ focusTabLoc: true }
article.querySelector("#post_1") ? 0 : articleTopPosition
);
}
@ -786,25 +786,11 @@ export default {
this._scrollTo(articleTopPosition - window.innerHeight * scrollRatio);
},
_scrollTo(scrollTop, opts = {}) {
_scrollTo(scrollTop) {
window.scrollTo({
top: scrollTop,
behavior: "smooth",
});
if (opts.focusTabLoc) {
window.addEventListener("scroll", this._onScrollEnds, { passive: true });
}
},
@bind
_onScrollEnds() {
window.removeEventListener("scroll", this._onScrollEnds, { passive: true });
discourseDebounce(this, this._onScrollEndsCallback, animationDuration);
},
_onScrollEndsCallback() {
document.querySelector(".topic-post.selected span.tabLoc")?.focus();
},
categoriesTopicsList() {

View File

@ -78,17 +78,18 @@ export function highlightPost(postNumber) {
return;
}
container.querySelector(".tabLoc")?.focus();
const element = container.querySelector(".topic-body");
const element = container.querySelector(".topic-body, .small-action-desc");
if (!element || element.classList.contains("highlighted")) {
return;
}
element.classList.add("highlighted");
element.setAttribute("tabindex", "0");
element.focus();
const removeHighlighted = function () {
element.classList.remove("highlighted");
element.removeAttribute("tabindex");
element.removeEventListener("animationend", removeHighlighted);
};
element.addEventListener("animationend", removeHighlighted);

View File

@ -190,9 +190,6 @@ export default createWidget("post-small-action", {
}
return [
h("span.tabLoc", {
attributes: { "aria-hidden": true, tabindex: -1 },
}),
h("div.topic-avatar", iconNode(icons[attrs.actionCode] || "exclamation")),
h("div.small-action-desc", [
h("div.small-action-contents", contents),

View File

@ -758,11 +758,7 @@ createWidget("post-article", {
},
html(attrs, state) {
const rows = [
h("span.tabLoc", {
attributes: { "aria-hidden": true, tabindex: -1 },
}),
];
const rows = [];
if (state.repliesAbove.length) {
const replies = state.repliesAbove.map((p) => {
return this.attach("embedded-post", p, {

View File

@ -11,6 +11,7 @@ import CategoryFixtures from "discourse/tests/fixtures/category-fixtures";
import topicFixtures from "discourse/tests/fixtures/topic";
import {
acceptance,
chromeTest,
count,
exists,
publishToMessageBus,
@ -412,18 +413,22 @@ acceptance("Topic featured links", function (needs) {
);
});
test("Quoting a quote with replyAsNewTopic keeps the original poster name", async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
await triggerKeyEvent(document, "keypress", "J");
await triggerKeyEvent(document, "keypress", "T");
// Using J/K on Firefox clean the text selection, so this won't work there
chromeTest(
"Quoting a quote with replyAsNewTopic keeps the original poster name",
async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
await triggerKeyEvent(document, "keypress", "J");
await triggerKeyEvent(document, "keypress", "T");
assert.ok(
query(".d-editor-input").value.includes(
'quote="codinghorror said, post:3, topic:280"'
)
);
});
assert.ok(
query(".d-editor-input").value.includes(
'quote="codinghorror said, post:3, topic:280"'
)
);
}
);
test("Quoting by selecting text can mark the quote as full", async function (assert) {
await visit("/t/internationalization-localization/280");

View File

@ -67,6 +67,7 @@
vertical-align: middle;
a {
color: var(--primary-high-or-secondary-low);
outline-offset: -1px;
}
}
.fa {
@ -941,11 +942,24 @@ aside.quote {
border-top: 1px solid var(--primary-low);
padding-top: 0.5em;
}
@media (prefers-reduced-motion: no-preference) {
&.highlighted {
animation: background-fade-highlight 2.5s ease-out;
}
}
}
.topic-body:not(.deleted),
.small-action-desc {
@media (prefers-reduced-motion: no-preference) {
&.highlighted {
animation: background-fade-highlight 2.5s ease-out;
}
}
&.highlighted:focus-visible {
outline: none;
}
.deleted & {
// Disable so the deleted background is visible immediately
&.highlighted {
@ -1140,6 +1154,10 @@ blockquote > *:last-child {
display: flex;
align-items: center;
&:focus-visible {
outline: none;
}
&.deleted {
background-color: var(--danger-low-mid);
}

View File

@ -3,20 +3,22 @@
border-left: 1px solid transparent;
}
.topic-list tr.selected td:first-child,
.topic-list-item.selected td:first-child,
.topic-list tr.selected,
.topic-list-item.selected,
.latest-topic-list-item.selected,
.search-results .fps-result.selected {
box-shadow: inset 3px 0 0 var(--danger); // needs to be inset for Edge
&:focus-visible {
outline: none;
}
}
.featured-topic.selected,
.topic-post.selected {
box-shadow: -3px 0 0 var(--danger);
}
.tabLoc:focus {
outline: none;
&:focus-visible {
outline: none;
}
}
.latest .featured-topic {