Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

Commit

Permalink
feat- make the modals accessible
Browse files Browse the repository at this point in the history
- all the modals meets the requirements of #24
- the code is reusable
 covers : #24, #20 and #21
  • Loading branch information
Jérémie Litzler committed Mar 9, 2018
1 parent 886fdaa commit ffca6a3
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 24 deletions.
Empty file modified CODEOWNERS
100644 → 100755
Empty file.
3 changes: 0 additions & 3 deletions css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,6 @@ nav h1 a {
}

@media screen and (min-width: 650px) {
.restaurant-hours-container-modal {
height: inherit;
}
.reviews-container-modal ul {
display: grid;
grid-template-columns: auto auto;
Expand Down
9 changes: 6 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ <h1>
</section>
<section class="restaurants-container">
<div id="filters" class="filter-options">
<button class="c-btn btn-default" title="Open the search" class="filter-list" href="#" onclick="document.getElementById('filters-modal').style.display='block'">Search</button>
<button class="c-btn btn-default open-search-modal js-filters-modal" title="Open the search" href="#">
Search
</button>
</div>
<ul id="restaurants-list"></ul>
</section>
Expand All @@ -36,18 +38,19 @@ <h1>
<strong>Restaurant Reviews</strong>
</a> All Rights Reserved.
</footer>
<div id="filters-modal" class="c-modal">
<div id="filters-modal" class="c-modal js-filters-modal">
<select tabindex="-1" id="neighborhoods-select" name="neighborhoods" onchange="updateRestaurants()">
<option value="all">All Neighborhoods</option>
</select>
<select id="cuisines-select" name="cuisines" onchange="updateRestaurants()">
<option value="all">All Cuisines</option>
</select>
<button class="c-btn btn-default" href="#" title="Close Search" onclick="document.getElementById('filters-modal').style.display='none'">Close Search</button>
<button class="c-btn btn-default js-close-modal" href="#" title="Close Search" onclick="document.getElementById('filters-modal').style.display='none'">Close Search</button>
</div>
<script type="application/javascript" charset="utf-8" src="js/app.js"></script>
<script type="application/javascript" charset="utf-8" src="js/dbhelper.js"></script>
<script type="application/javascript" charset="utf-8" src="js/main.js"></script>
<script type="application/javascript" charset="utf-8" src="js/focus.handler.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBXysE433qRY0W9gup0-_N5UF_0ObJK3oc&libraries=places&callback=initMap"></script>
</body>

Expand Down
115 changes: 115 additions & 0 deletions js/focus.handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//Store the element focused before opening the modal.
//When the modal is closed, the focus will be restored to that element.
let focusedElementBeforeModal;

let openModalBtnTriggered;
let openSearchModalBtn = document.querySelector(".open-search-modal");
let openHoursModalBtn = document.querySelector(".open-hours-modal");
let openReviewsModalBtn = document.querySelector(".open-reviews-modal");

if (openSearchModalBtn != null) {
openSearchModalBtn.addEventListener("click", function() {
openModalBtnTriggered = openSearchModalBtn;
openModal();
});
}
if (openHoursModalBtn != null) {
openHoursModalBtn.addEventListener("click", function() {
openModalBtnTriggered = openHoursModalBtn;
openModal();
});
}
if (openReviewsModalBtn != null) {
openReviewsModalBtn.addEventListener("click", function() {
openModalBtnTriggered = openReviewsModalBtn;
openModal();
});
}

function openModal() {
const targetModal = findTargetModal(openModalBtnTriggered);

//Save the current active element.
focusedElementBeforeModal = document.activeElement;

//Listen for and trap the keyboard
targetModal.addEventListener("keydown", trapTabKey);

//Close button handler
const closeModalBtn = targetModal.querySelector(".js-close-modal");
closeModalBtn.addEventListener("click", function() {
closeModal(targetModal);
});

//Find all focusable children that we can find in the modal.
const focusableElementsString = `a[href], area[href],
input:not([disabled]), select:not([disabled]),
textarea:not([disabled]), button:not([disabled]), iframe,
object, embed, [tabindex="0"], [contenteditable]`;

let focusableElements = targetModal.querySelectorAll(focusableElementsString);

//Convert NodeList to Array
focusableElements = Array.prototype.slice.call(focusableElements);

//Get the first item in the modal's focusable elements that we will use as sentinals
//to restart the focus loop
const firstTabStop = focusableElements[0];
//... and the last one.
const lastTabStop = focusableElements[focusableElements.length - 1];

//Show the modal
targetModal.style.display = "block";

firstTabStop.focus();
function trapTabKey(event) {
//Check for TAB key press
if (event.keyCode === 9) {
if (handleShitfTab(event)) {
return;
}

if (document.activeElement == lastTabStop) {
event.preventDefault();
firstTabStop.focus();
}
}
if (event.keyCode === 27) {
closeModal(targetModal);
}
}
function handleShitfTab(event) {
if (event.shiftKey && document.activeElement === firstTabStop) {
event.preventDefault();
lastTabStop.focus();
return true;
}
return false;
}
}

function findTargetModal(clickedBtn) {
const openModalBtnClassesArray = Array.prototype.slice.call(
clickedBtn.classList
);
const targetModalClass =
openModalBtnClassesArray[openModalBtnClassesArray.length - 1];

const availableModals = document.querySelectorAll(".c-modal");
console.log("availableModals", availableModals);
let targetModal;
for (const modal of availableModals) {
const modalClassArray = Array.prototype.slice.call(modal.classList);
if (modalClassArray.includes(targetModalClass)) {
console.log("found target", targetModal);
return modal;
}
}
throw "Modal wasn't found!";
}
function closeModal(targetModal) {
targetModal.style.display = "none";

//Restore focus to the element that was focused before opening the modal.
focusedElementBeforeModal.focus();
}
39 changes: 21 additions & 18 deletions restaurant.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</head>

<body class="inside">

<a href="#restaurant-actions" class="c-skip-link c-btn">View opening hours</a>
<header>
<h1>
<a class="c-link-on-dark" href="/">Restaurant Reviews</a>
Expand All @@ -25,40 +25,41 @@ <h1>
</ul>

<main id="maincontent" class="resto-page-container">
<!-- Beginning restaurant -->

<section id="restaurant-container" class="restaurant-details-container">
<h1 id="restaurant-name"></h1>
<p id="restaurant-cuisine"></p>
<p id="restaurant-address"></p>
<div class="restaurant-img-container">
<img id="restaurant-img">
</div>
<button class="c-btn btn-default btn-resto-hours" title="View opening hours" onclick="document.getElementById('restaurant-hours').style.display='block'">
View opening hours
</button>
<section id="restaurant-hours" class="restaurant-hours-container-modal">
<h2>Opening hours</h2>
<table id="restaurant-hours-table"></table>
<button class="c-btn btn-default" title="Close" onclick="document.getElementById('restaurant-hours').style.display='none'">
Toggle
<div id="restaurant-actions">
<button class="c-btn btn-default btn-resto-hours open-hours-modal js-restaurant-hours-modal" title="View opening hours">
View opening hours
</button>
</section>
<button class="c-btn btn-default open-reviews-modal js-reviews-modal" title="Read reviews">
Read reviews
</button>
</div>
</section>

<button class="c-btn btn-default" title="Read reviews" onclick="document.getElementById('reviews-container').style.display='block'">
Read reviews
<section id="restaurant-hours" class="c-modal restaurant-hours-container-modal js-restaurant-hours-modal">
<h2>Opening hours</h2>
<table id="restaurant-hours-table"></table>
<button class="c-btn btn-default js-close-modal" title="Close" onclick="document.getElementById('restaurant-hours').style.display='none'">
Close
</button>
</section>
<!-- end restaurant -->
<!-- Beginning reviews -->
<section id="reviews-container" class="c-modal reviews-container-modal">

<section id="reviews-container" class="c-modal reviews-container-modal js-reviews-modal">
<ul id="reviews-list"></ul>
<div class="btn-close-modal">
<div class="btn-close-modal js-close-modal">
<button class="c-btn btn-default" title="Close" onclick="document.getElementById( 'reviews-container').style.display='none'">
Close
</button>
</div>
</section>
<!-- End reviews -->

<!-- Beginning map -->
<section class="map-container">
<div id="map" aria-hidden="true"></div>
Expand All @@ -80,6 +81,8 @@ <h2>Opening hours</h2>
<script type="text/javascript" src="js/dbhelper.js"></script>
<!-- Main javascript file -->
<script type="text/javascript" src="js/restaurant_info.js"></script>
<script type="application/javascript" charset="utf-8" src="js/focus.handler.js"></script>

<!-- Google Maps -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBXysE433qRY0W9gup0-_N5UF_0ObJK3oc&libraries=places&callback=initMap"></script>
<!-- End scripts -->
Expand Down

0 comments on commit ffca6a3

Please sign in to comment.