Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility improvements #1

Merged
merged 29 commits into from Oct 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8f0c02e
Add proper links in the menu
leonardofaria Sep 20, 2019
15132a9
Update page title when clicking a link
leonardofaria Sep 20, 2019
1cc2113
Merge branch 'master' into accessibility-improvements
leonardofaria Sep 21, 2019
b947378
Improve history button
leonardofaria Sep 21, 2019
203a08e
Improve semantic markup
leonardofaria Sep 21, 2019
ac5d81d
Add descriptions in tables
leonardofaria Sep 21, 2019
15aa0bb
Add link classes to highlight them
leonardofaria Sep 21, 2019
cb25726
Make modal accessible
leonardofaria Sep 21, 2019
8a9a540
Merge branch 'master' into accessibility-improvements
leonardofaria Sep 22, 2019
186120e
Add banner role
leonardofaria Sep 22, 2019
5254b9a
Fix mobile menu markup
leonardofaria Sep 22, 2019
7df45ea
Add spacing between paragraphs to improve readability
leonardofaria Sep 22, 2019
bcc2f1f
Add alternative text in images
leonardofaria Sep 22, 2019
97c7ebb
Merge branch 'master' into accessibility-improvements
leonardofaria Sep 22, 2019
ccb2b44
Merge branch 'master' into accessibility-improvements
leonardofaria Sep 22, 2019
7c6c7e2
Fix modal in mobile devices
leonardofaria Sep 22, 2019
f981391
Merge branch 'master' into accessibility-improvements
leonardofaria Sep 22, 2019
6756e15
Merge branch 'master' into accessibility-improvements
leonardofaria Sep 28, 2019
a8be40d
Add missing label
leonardofaria Oct 5, 2019
08c529f
Add table scope and title attribute
leonardofaria Oct 5, 2019
e2c3bcf
Fix aria-hidden attribute (reported by axe)
leonardofaria Oct 5, 2019
5ba15e0
Fix colour contrast (reported by axe)
leonardofaria Oct 5, 2019
70362d8
Remove unnecessary banner (reported by axe)
leonardofaria Oct 5, 2019
dd467ed
Add focus to scrollable items (reported by axe)
leonardofaria Oct 5, 2019
ed9b106
Fix colour contrast (reported by axe)
leonardofaria Oct 5, 2019
47da8b5
Remove duplicated menu
leonardofaria Oct 11, 2019
a1a42ca
Adjust notes block
leonardofaria Oct 11, 2019
dde1b2e
Merge branch 'master' into accessibility-improvements
leonardofaria Oct 17, 2019
fcb33f5
Format code with Prettier
leonardofaria Oct 17, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
159 changes: 63 additions & 96 deletions app.js
@@ -1,155 +1,122 @@
const body = document.body;
const modal = document.querySelector('.modal');
const navDialogEl = document.querySelector(".dialog");
const dialogOverlay = document.querySelector(".dialog-overlay");

const openModal = document.querySelectorAll('.modal-open');
const closeModal = document.querySelectorAll('.modal-close');
const overlay = document.querySelector('.modal-overlay');

const toggleModal = function() {
modal.classList.toggle('opacity-0');
modal.classList.toggle('pointer-events-none');
body.classList.toggle('modal-active');
};

for (let i = 0; i < openModal.length; i++) {
openModal[i].addEventListener('click', function(event) {
event.preventDefault();
toggleModal();
});
};

for (let i = 0; i < closeModal.length; i++) {
closeModal[i].addEventListener('click', toggleModal);
}

overlay.addEventListener('click', toggleModal);

document.onkeydown = function(evt) {
evt = evt || window.event;
let isEscape = false;

if ("key" in evt) {
isEscape = (evt.key === "Escape" || evt.key === "Esc");
} else {
isEscape = (evt.keyCode === 27);
}
if (isEscape && document.body.classList.contains('modal-active')) {
toggleModal();
}
};
const myDialog = new Dialog(navDialogEl, dialogOverlay);
myDialog.addEventListeners(".open-dialog", ".close-dialog");

const menuButton = document.getElementById("menu-button");
const menuContainer = document.getElementById("menu-container");

const menuButton = document.getElementById('menu-button');
const menuContainer = document.getElementById('menu-container');

menuButton.addEventListener('click', function(event) {
menuContainer.classList.toggle('hidden');
menuButton.addEventListener("click", function(event) {
menuContainer.classList.toggle("hidden");
});


const computersButton = document.querySelectorAll('.computers-button');
const computersContainer = document.getElementById('computers-container');
const computersCards = document.getElementById('computers-cards');
const computersGrid = document.getElementById('computers-grid');
const idevicesButton = document.querySelectorAll('.idevices-button');
const idevicesContainer = document.getElementById('idevices-container');
const idevicesCards = document.getElementById('idevices-cards');
const idevicesGrid = document.getElementById('idevices-grid');
const collectionLabel = document.getElementById('collection-label');
const uiButtons = document.querySelectorAll('.computers-button, .idevices-button');
const modeButtons = document.querySelectorAll('.mode-button');
const computersButton = document.querySelectorAll(".computers-button");
const computersContainer = document.getElementById("computers-container");
const computersCards = document.getElementById("computers-cards");
const computersGrid = document.getElementById("computers-grid");
const idevicesButton = document.querySelectorAll(".idevices-button");
const idevicesContainer = document.getElementById("idevices-container");
const idevicesCards = document.getElementById("idevices-cards");
const idevicesGrid = document.getElementById("idevices-grid");
const collectionLabel = document.getElementById("collection-label");
const uiButtons = document.querySelectorAll(
".computers-button, .idevices-button"
);
const modeButtons = document.querySelectorAll(".mode-button");

const showCollection = function(collection) {
let items = null;
let label = null;

if (collection === 'computers') {
items = document.querySelectorAll('#computers-container .card');
label = 'Computers (' + items.length + ')';
idevicesContainer.classList.add('hidden');
computersContainer.classList.remove('hidden');
if (collection === "computers") {
items = document.querySelectorAll("#computers-container .card");
label = "Computers (" + items.length + ")";
idevicesContainer.classList.add("hidden");
computersContainer.classList.remove("hidden");
} else {
items = document.querySelectorAll('#idevices-container .card');
label = 'iDevices (' + items.length + ')';
idevicesContainer.classList.remove('hidden');
computersContainer.classList.add('hidden');
items = document.querySelectorAll("#idevices-container .card");
label = "iDevices (" + items.length + ")";
idevicesContainer.classList.remove("hidden");
computersContainer.classList.add("hidden");
}

uiButtons.forEach(function(element) {
const dataCollection = element.dataset.collection;
if (dataCollection === collection) {
element.classList.remove('text-gray-800');
element.classList.add('text-purple-600');
element.classList.remove("text-gray-800");
element.classList.add("text-purple-800");
} else {
element.classList.add('text-gray-800');
element.classList.remove('text-purple-600');
element.classList.add("text-gray-800");
element.classList.remove("text-purple-800");
}
});

collectionLabel.innerHTML = label;

const params = new URLSearchParams(location.search);
params.set('collection', collection);
window.history.replaceState({}, '', `${location.pathname}?${params}`);
params.set("collection", collection);
window.history.replaceState({}, "", `${location.pathname}?${params}`);
// TODO: replaceState is not updating the title
document.title = `${label} - Leo's Collection`;

// Mobile: close menu after click
if (!menuContainer.classList.contains('hidden')) {
menuContainer.classList.add('hidden');
if (!menuContainer.classList.contains("hidden")) {
menuContainer.classList.add("hidden");
}
}
};

uiButtons.forEach(function(element) {
element.addEventListener('click', function(event) {
element.addEventListener("click", function(event) {
const collection = element.dataset.collection;
showCollection(collection);

event.preventDefault();
});
});

const toggleMode = function(mode) {
if (mode === 'grid') {
computersCards.classList.add('hidden');
idevicesCards.classList.add('hidden');
computersGrid.classList.remove('hidden');
idevicesGrid.classList.remove('hidden');
if (mode === "grid") {
computersCards.classList.add("hidden");
idevicesCards.classList.add("hidden");
computersGrid.classList.remove("hidden");
idevicesGrid.classList.remove("hidden");
} else {
computersCards.classList.remove('hidden');
idevicesCards.classList.remove('hidden');
computersGrid.classList.add('hidden');
idevicesGrid.classList.add('hidden');
computersCards.classList.remove("hidden");
idevicesCards.classList.remove("hidden");
computersGrid.classList.add("hidden");
idevicesGrid.classList.add("hidden");
}

modeButtons.forEach(function(button) {
const dataMode = button.dataset.mode;
if (dataMode === mode) {
button.classList.remove('text-gray-800');
button.classList.add('text-purple-600');
button.classList.remove("text-gray-800");
button.classList.add("text-purple-800");
} else {
button.classList.add('text-gray-800');
button.classList.remove('text-purple-600');
button.classList.add("text-gray-800");
button.classList.remove("text-purple-800");
}
});

const params = new URLSearchParams(location.search);
params.set('mode', mode);
window.history.replaceState({}, '', `${location.pathname}?${params}`);
}
params.set("mode", mode);
window.history.replaceState({}, "", `${location.pathname}?${params}`);
};

modeButtons.forEach(function(element) {
element.addEventListener('click', function(event) {
element.addEventListener("click", function(event) {
const mode = element.dataset.mode;
toggleMode(mode);
});
});


const params = new URLSearchParams(location.search);

if (params.get('collection')) {
showCollection(params.get('collection'));
if (params.get("collection")) {
showCollection(params.get("collection"));
}

if (params.get('mode')) {
toggleMode(params.get('mode'));
if (params.get("mode")) {
toggleMode(params.get("mode"));
}
108 changes: 108 additions & 0 deletions dialog.js
@@ -0,0 +1,108 @@
// Acessible dialog by Ire Aderinokun
// https://bitsofco.de/accessible-modal-dialog/

function Dialog(dialogEl, overlayEl) {
this.dialogEl = dialogEl;
this.overlayEl = overlayEl;
this.focusedElBeforeOpen;

var focusableEls = this.dialogEl.querySelectorAll(
'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"]'
);
this.focusableEls = Array.prototype.slice.call(focusableEls);

this.firstFocusableEl = this.focusableEls[0];
this.lastFocusableEl = this.focusableEls[this.focusableEls.length - 1];

this.close(); // Reset
}

Dialog.prototype.open = function() {
var Dialog = this;

this.dialogEl.removeAttribute("aria-hidden");
this.dialogEl.classList.remove("hidden");
this.overlayEl.removeAttribute("aria-hidden");
this.overlayEl.classList.remove("hidden");
document.body.classList.add("overflow-hidden");

this.focusedElBeforeOpen = document.activeElement;

this.dialogEl.addEventListener("keydown", function(e) {
Dialog._handleKeyDown(e);
});

this.overlayEl.addEventListener("click", function() {
Dialog.close();
});

this.firstFocusableEl.focus();
};

Dialog.prototype.close = function() {
this.dialogEl.setAttribute("aria-hidden", true);
this.dialogEl.classList.add("hidden");
this.overlayEl.setAttribute("aria-hidden", true);
this.overlayEl.classList.add("hidden");
document.body.classList.remove("overflow-hidden");

if (this.focusedElBeforeOpen) {
this.focusedElBeforeOpen.focus();
}
};

Dialog.prototype._handleKeyDown = function(e) {
var Dialog = this;
var KEY_TAB = 9;
var KEY_ESC = 27;

function handleBackwardTab() {
if (document.activeElement === Dialog.firstFocusableEl) {
e.preventDefault();
Dialog.lastFocusableEl.focus();
}
}
function handleForwardTab() {
if (document.activeElement === Dialog.lastFocusableEl) {
e.preventDefault();
Dialog.firstFocusableEl.focus();
}
}

switch (e.keyCode) {
case KEY_TAB:
if (Dialog.focusableEls.length === 1) {
e.preventDefault();
break;
}
if (e.shiftKey) {
handleBackwardTab();
} else {
handleForwardTab();
}
break;
case KEY_ESC:
Dialog.close();
break;
default:
break;
}
};

Dialog.prototype.addEventListeners = function(openDialogSel, closeDialogSel) {
var Dialog = this;

var openDialogEls = document.querySelectorAll(openDialogSel);
for (var i = 0; i < openDialogEls.length; i++) {
openDialogEls[i].addEventListener("click", function() {
Dialog.open();
});
}

var closeDialogEls = document.querySelectorAll(closeDialogSel);
for (var i = 0; i < closeDialogEls.length; i++) {
closeDialogEls[i].addEventListener("click", function() {
Dialog.close();
});
}
};