Skip to content

Commit 649be7c

Browse files
authored
chore(a11y): misc a11y improvements (#4211)
1 parent f19007f commit 649be7c

File tree

21 files changed

+136
-23
lines changed

21 files changed

+136
-23
lines changed

extensions/approval/js/src/forum/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ app.initializers.add(
1818
if (!this.isApproved() && !items.has('hidden')) {
1919
items.add(
2020
'awaitingApproval',
21-
<Badge type="awaitingApproval" icon="fas fa-gavel" label={app.translator.trans('flarum-approval.forum.badge.awaiting_approval_tooltip')} />
21+
<Badge
22+
type="awaitingApproval"
23+
icon="fas fa-gavel"
24+
label={app.translator.trans('flarum-approval.forum.badge.awaiting_approval_tooltip')}
25+
tabindex="0"
26+
/>
2227
);
2328
}
2429
});

extensions/lock/js/src/forum/addLockBadge.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import Badge from 'flarum/common/components/Badge';
66
export default function addLockBadge() {
77
extend(Discussion.prototype, 'badges', function (badges) {
88
if (this.isLocked()) {
9-
badges.add('locked', <Badge type="locked" label={app.translator.trans('flarum-lock.forum.badge.locked_tooltip')} icon="fas fa-lock" />);
9+
badges.add(
10+
'locked',
11+
<Badge type="locked" label={app.translator.trans('flarum-lock.forum.badge.locked_tooltip')} icon="fas fa-lock" tabindex="0" />
12+
);
1013
}
1114
});
1215
}

extensions/sticky/js/src/forum/addStickyBadge.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default function addStickyBadge() {
88
if (this.isSticky()) {
99
badges.add(
1010
'sticky',
11-
<Badge type="sticky" label={app.translator.trans('flarum-sticky.forum.badge.sticky_tooltip')} icon="fas fa-thumbtack" />,
11+
<Badge type="sticky" label={app.translator.trans('flarum-sticky.forum.badge.sticky_tooltip')} icon="fas fa-thumbtack" tabindex="0" />,
1212
10
1313
);
1414
}

extensions/subscriptions/js/src/forum/addSubscriptionBadge.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,25 @@ export default function addSubscriptionBadge() {
99

1010
switch (this.subscription()) {
1111
case 'follow':
12-
badge = <Badge label={app.translator.trans('flarum-subscriptions.forum.badge.following_tooltip')} icon="fas fa-star" type="following" />;
12+
badge = (
13+
<Badge
14+
label={app.translator.trans('flarum-subscriptions.forum.badge.following_tooltip')}
15+
icon="fas fa-star"
16+
type="following"
17+
tabindex="0"
18+
/>
19+
);
1320
break;
1421

1522
case 'ignore':
16-
badge = <Badge label={app.translator.trans('flarum-subscriptions.forum.badge.ignoring_tooltip')} icon="far fa-eye-slash" type="ignoring" />;
23+
badge = (
24+
<Badge
25+
label={app.translator.trans('flarum-subscriptions.forum.badge.ignoring_tooltip')}
26+
icon="far fa-eye-slash"
27+
type="ignoring"
28+
tabindex="0"
29+
/>
30+
);
1731
break;
1832
}
1933

extensions/suspend/js/src/forum/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ app.initializers.add('flarum-suspend', () => {
2828
if (new Date() < until) {
2929
items.add(
3030
'suspended',
31-
<Badge icon="fas fa-ban" type="suspended" label={app.translator.trans('flarum-suspend.forum.user_badge.suspended_tooltip')} />,
31+
<Badge icon="fas fa-ban" type="suspended" label={app.translator.trans('flarum-suspend.forum.user_badge.suspended_tooltip')} tabindex="0" />,
3232
100
3333
);
3434
}

framework/core/js/src/common/Application.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import IExtender from './extenders/IExtender';
3939
import AccessToken from './models/AccessToken';
4040
import SearchManager from './SearchManager';
4141
import { ColorScheme } from './components/ThemeMode';
42+
import { prepareSkipLinks } from './utils/a11y';
4243

4344
export type FlarumScreens = 'phone' | 'tablet' | 'desktop' | 'desktop-hd';
4445

@@ -394,6 +395,8 @@ export default class Application {
394395
this.initColorScheme();
395396

396397
liveHumanTimes();
398+
399+
prepareSkipLinks();
397400
}
398401

399402
private initColorScheme(forumDefault: string | null = null): void {

framework/core/js/src/common/components/Dropdown.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ export default class Dropdown<CustomAttrs extends IDropdownAttrs = IDropdownAttr
123123

124124
m.redraw();
125125
});
126+
127+
this.$().on('focusout', (e: JQuery.FocusOutEvent) => {
128+
// Check if the new focused element is outside of this dropdown
129+
if (!this.$().has(e.relatedTarget as Element).length) {
130+
this.$().trigger('hidden.bs.dropdown');
131+
}
132+
});
133+
// Focusing out of the dropdown should close it.
126134
}
127135

128136
/**

framework/core/js/src/common/models/Discussion.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export default class Discussion extends Model {
131131
const items = new ItemList<Mithril.Children>();
132132

133133
if (this.isHidden()) {
134-
items.add('hidden', <Badge type="hidden" icon="fas fa-trash" label={app.translator.trans('core.lib.badge.hidden_tooltip')} />);
134+
items.add('hidden', <Badge type="hidden" icon="fas fa-trash" label={app.translator.trans('core.lib.badge.hidden_tooltip')} tabindex="0" />);
135135
}
136136

137137
return items;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Fix a11y skip links by manually focusing on the href target element.
3+
* This prevents unwanted/unexpected reloads of the page.
4+
*/
5+
export function prepareSkipLinks() {
6+
document.querySelectorAll('.sr-only-focusable-custom:not([data-prepared])').forEach((el) => {
7+
el.addEventListener('click', function (e) {
8+
e.preventDefault();
9+
const target = el.getAttribute('href')!;
10+
const $target = document.querySelector(target) as HTMLElement;
11+
12+
if ($target) {
13+
$target.setAttribute('tabindex', '-1');
14+
$target.focus();
15+
$target.removeAttribute('tabindex');
16+
17+
$target.dataset.prepared = 'true';
18+
}
19+
});
20+
});
21+
}

framework/core/js/src/forum/components/AvatarEditor.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ export default class AvatarEditor extends Component {
4242
return (
4343
<div className={classList(['AvatarEditor', 'Dropdown', this.attrs.className, this.loading && 'loading', this.isDraggedOver && 'dragover'])}>
4444
<Avatar user={user} loading="eager" />
45-
<a
45+
<button
4646
className={user.avatarUrl() ? 'Dropdown-toggle' : 'Dropdown-toggle AvatarEditor--noAvatar'}
4747
title={app.translator.trans('core.forum.user.avatar_upload_tooltip')}
48+
ariaLabel={app.translator.trans('core.forum.user.avatar_upload_tooltip')}
4849
data-toggle="dropdown"
4950
onclick={this.quickUpload.bind(this)}
5051
ondragover={this.enableDragover.bind(this)}
@@ -60,7 +61,7 @@ export default class AvatarEditor extends Component {
6061
) : (
6162
<Icon name={'fas fa-plus-circle'} />
6263
)}
63-
</a>
64+
</button>
6465
<ul className="Dropdown-menu Menu">{listItems(this.controlItems().toArray())}</ul>
6566
</div>
6667
);

0 commit comments

Comments
 (0)