Optimise dropdowns for accessibility - Profile page (#13916)
* use initializedropdown in profileDropdown * improve aria in html * add cypress tests, stop buttons and dropdown initializing twice or more * make sure dropdown shows when logged out
This commit is contained in:
parent
a7159b84f8
commit
f607cf8722
5 changed files with 156 additions and 44 deletions
|
|
@ -7,7 +7,7 @@
|
|||
initializeCommentPreview, initializeRuntimeBanner,
|
||||
initializeTimeFixer, initializeDashboardSort, initializePWAFunctionality,
|
||||
initializeArchivedPostFilter, initializeCreditsPage,
|
||||
initializeUserProfilePage, initializeProfileInfoToggle, initializePodcastPlayback,
|
||||
initializeProfileInfoToggle, initializePodcastPlayback,
|
||||
initializeVideoPlayback, initializeDrawerSliders, initializeProfileBadgesToggle,
|
||||
initializeHeroBannerClose, initializeOnboardingTaskCard, initScrolling,
|
||||
nextPage:writable, fetching:writable, done:writable, adClicked:writable,
|
||||
|
|
@ -31,7 +31,6 @@ function callInitializers() {
|
|||
initializePWAFunctionality();
|
||||
initializeArchivedPostFilter();
|
||||
initializeCreditsPage();
|
||||
initializeUserProfilePage();
|
||||
initializeProfileInfoToggle();
|
||||
initializeProfileBadgesToggle();
|
||||
initializePodcastPlayback();
|
||||
|
|
|
|||
|
|
@ -1,39 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
function initializeUserProfilePage() {
|
||||
const profileDropdownDiv = document.getElementsByClassName(
|
||||
'profile-dropdown',
|
||||
)[0];
|
||||
if (profileDropdownDiv) {
|
||||
const currentUser = userData();
|
||||
if (
|
||||
currentUser &&
|
||||
currentUser.username === profileDropdownDiv.dataset.username
|
||||
) {
|
||||
profileDropdownDiv.hidden = true;
|
||||
} else {
|
||||
profileDropdownDiv.hidden = false;
|
||||
const userProfileDropdownButton = document.getElementById(
|
||||
'user-profile-dropdown',
|
||||
);
|
||||
if (userProfileDropdownButton) {
|
||||
const userProfileDropdownMenu = document.getElementById(
|
||||
'user-profile-dropdownmenu',
|
||||
);
|
||||
userProfileDropdownButton.addEventListener('click', () => {
|
||||
userProfileDropdownMenu.classList.toggle('block');
|
||||
|
||||
// Add actual link location (SEO doesn't like these "useless" links, so adding in here instead of in HTML)
|
||||
var reportAbuseLink = profileDropdownDiv.getElementsByClassName(
|
||||
'report-abuse-link-wrapper',
|
||||
)[0];
|
||||
reportAbuseLink.innerHTML = `<a href="${reportAbuseLink.dataset.path}" class="crayons-link crayons-link--block">Report Abuse</a>`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeProfileInfoToggle() {
|
||||
const infoPanels = document.getElementsByClassName('js-user-info')[0];
|
||||
const trigger = document.getElementsByClassName('js-user-info-trigger')[0];
|
||||
|
|
|
|||
|
|
@ -1,13 +1,46 @@
|
|||
import { initBlock } from '../profileDropdown/blockButton';
|
||||
import { initFlag } from '../profileDropdown/flagButton';
|
||||
import { initializeDropdown } from '@utilities/dropdownUtils';
|
||||
|
||||
/* global userData */
|
||||
|
||||
function initButtons() {
|
||||
initBlock();
|
||||
initFlag();
|
||||
}
|
||||
|
||||
window.InstantClick.on('change', () => {
|
||||
initButtons();
|
||||
});
|
||||
function initDropdown() {
|
||||
const profileDropdownDiv = document.querySelector('.profile-dropdown');
|
||||
|
||||
initButtons();
|
||||
if (profileDropdownDiv.dataset.dropdownInitialized === 'true') {
|
||||
return;
|
||||
}
|
||||
const currentUser = userData();
|
||||
|
||||
if (
|
||||
!profileDropdownDiv ||
|
||||
(currentUser &&
|
||||
currentUser.username === profileDropdownDiv.dataset.username)
|
||||
) {
|
||||
// Hide this menu when user views their own profile
|
||||
return;
|
||||
}
|
||||
|
||||
profileDropdownDiv.classList.remove('hidden');
|
||||
|
||||
initializeDropdown({
|
||||
triggerElementId: 'user-profile-dropdown',
|
||||
dropdownContentId: 'user-profile-dropdownmenu',
|
||||
});
|
||||
|
||||
// Add actual link location (SEO doesn't like these "useless" links, so adding in here instead of in HTML)
|
||||
const reportAbuseLink = profileDropdownDiv.querySelector(
|
||||
'.report-abuse-link-wrapper',
|
||||
);
|
||||
reportAbuseLink.innerHTML = `<a href="${reportAbuseLink.dataset.path}" class="crayons-link crayons-link--block">Report Abuse</a>`;
|
||||
|
||||
initButtons();
|
||||
profileDropdownDiv.dataset.dropdownInitialized = true;
|
||||
}
|
||||
|
||||
initDropdown();
|
||||
|
|
|
|||
|
|
@ -27,12 +27,13 @@
|
|||
</span>
|
||||
|
||||
<div class="profile-header__actions">
|
||||
<div class="profile-dropdown mr-2 relative" data-username="<%= @user.username %>">
|
||||
<button id="user-profile-dropdown" class="crayons-btn crayons-btn--ghost-dimmed crayons-btn--icon">
|
||||
<%= inline_svg_tag("overflow-horizontal.svg", class: "dropdown-icon crayons-icon", aria: true, title: "Toggle dropdown menu") %>
|
||||
<div class="profile-dropdown mr-2 relative hidden" data-username="<%= @user.username %>">
|
||||
<button id="user-profile-dropdown" aria-expanded="false" aria-controls="user-profile-dropdownmenu" aria-haspopup="true" class="crayons-btn crayons-btn--ghost-dimmed crayons-btn--icon">
|
||||
<%= inline_svg_tag("overflow-horizontal.svg", class: "dropdown-icon crayons-icon", aria: true, title: "User actions") %>
|
||||
</button>
|
||||
|
||||
<div id="user-profile-dropdownmenu" class="crayons-dropdown top-100 right-0 p-1">
|
||||
<%= javascript_packs_with_chunks_tag "profileDropdown", defer: true %>
|
||||
<% if user_signed_in? %>
|
||||
<a href="javascript:void(0);" id="user-profile-dropdownmenu-block-button" data-profile-user-id="<%= @user.id %>" class="border-none crayons-link crayons-link--block">Block @<%= @user.username %></a>
|
||||
<a
|
||||
|
|
@ -44,7 +45,6 @@
|
|||
class="border-none crayons-link crayons-link--block">
|
||||
<%= @flag_status ? "Unflag" : "Flag" %> @<%= @user.username %>
|
||||
</a>
|
||||
<%= javascript_packs_with_chunks_tag "profileDropdown", defer: true %>
|
||||
<% end %>
|
||||
<span class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= user_url(@user) %>"></span>
|
||||
</div>
|
||||
|
|
|
|||
114
cypress/integration/profileFlows/profileUserActionsMenu.spec.js
Normal file
114
cypress/integration/profileFlows/profileUserActionsMenu.spec.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
describe('Profile User Actions Menu', () => {
|
||||
describe('Logged in users', () => {
|
||||
beforeEach(() => {
|
||||
cy.testSetup();
|
||||
cy.fixture('users/adminUser.json').as('user');
|
||||
|
||||
cy.get('@user').then((user) => {
|
||||
cy.loginUser(user).then(() => {
|
||||
cy.visit('/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should show a dropdown menu when a user views another user's profile", () => {
|
||||
cy.visit('/article_editor_v1_user');
|
||||
|
||||
cy.findByRole('button', { name: 'User actions' }).as('dropdownButton');
|
||||
cy.get('@dropdownButton').click();
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' }).should(
|
||||
'have.focus',
|
||||
);
|
||||
cy.findByRole('link', { name: 'Flag @article_editor_v1_user' });
|
||||
cy.findByRole('link', { name: 'Report Abuse' });
|
||||
|
||||
// Check the menu can be closed by click
|
||||
cy.get('@dropdownButton').click();
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
|
||||
// Check the menu can be closed by escape press
|
||||
cy.get('@dropdownButton').click();
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' });
|
||||
cy.get('body').type('{esc}');
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
cy.get('@dropdownButton').should('have.focus');
|
||||
});
|
||||
|
||||
it('should not show a dropdown menu when a user views their own profile', () => {
|
||||
cy.visit('/admin_mcadmin');
|
||||
cy.findByRole('button', { name: 'User actions' }).should('not.exist');
|
||||
});
|
||||
|
||||
it('should block and unblock a user', () => {
|
||||
// Always accept the confirmation that pops up
|
||||
cy.on('window:confirm', () => true);
|
||||
|
||||
cy.visit('/article_editor_v1_user');
|
||||
cy.findByRole('button', { name: 'User actions' }).click();
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' }).click();
|
||||
|
||||
// Check that the menu option has updated, and unblock user
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
cy.findByRole('link', { name: 'Unblock' }).click();
|
||||
|
||||
cy.findByRole('link', { name: 'Unblock' }).should('not.exist');
|
||||
cy.findByRole('link', { name: 'Block' });
|
||||
});
|
||||
|
||||
it('should flag and unflag a user', () => {
|
||||
// Always accept the confirmation that pops up
|
||||
cy.on('window:confirm', () => true);
|
||||
|
||||
cy.visit('/article_editor_v1_user');
|
||||
cy.findByRole('button', { name: 'User actions' }).click();
|
||||
cy.findByRole('link', { name: 'Flag @article_editor_v1_user' }).click();
|
||||
|
||||
// Check that the menu option has updated
|
||||
cy.findByRole('link', { name: 'Flag @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
cy.findByRole('link', { name: 'Unflag @article_editor_v1_user' }).click();
|
||||
|
||||
// Check that the menu option has updated
|
||||
cy.findByRole('link', { name: 'Unflag @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
cy.findByRole('link', { name: 'Flag @article_editor_v1_user' });
|
||||
});
|
||||
|
||||
it('should link to report abuse from user', () => {
|
||||
cy.visit('/article_editor_v1_user');
|
||||
cy.findByRole('button', { name: 'User actions' }).click();
|
||||
cy.findByRole('link', { name: 'Report Abuse' }).click();
|
||||
|
||||
cy.url().should('contain', 'report-abuse');
|
||||
cy.url().should('contain', 'article_editor_v1_user');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Logged out users', () => {
|
||||
beforeEach(() => {
|
||||
cy.testSetup();
|
||||
});
|
||||
|
||||
it('should show a dropdown menu with only the Report Abuse link when the user is not logged in', () => {
|
||||
cy.visit('/article_editor_v1_user');
|
||||
cy.findByRole('button', { name: 'User actions' }).click();
|
||||
|
||||
cy.findByRole('link', { name: 'Report Abuse' }).should('have.focus');
|
||||
|
||||
cy.findByRole('link', { name: 'Block @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
cy.findByRole('link', { name: 'Flag @article_editor_v1_user' }).should(
|
||||
'not.exist',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue