From 07444720b97c8225d81a96dbd4322957027aa503 Mon Sep 17 00:00:00 2001 From: Robert Lange <robert.lange@uni-leipzig.de> Date: Tue, 22 Nov 2022 13:32:48 +0100 Subject: [PATCH] refs #22564 [finc] keep focus within offcanvas * close canvas on escape key * set focus on search-filter-toggle after closing facet sidebar * fix skip link to sidebar facets * fix skip link to sidebar facets - hide on mobile * set focus on search-filter-toggle after closing facet sidebar * TODO: check instances with "offcanvas = false" like de_l152 after VF6-upgrade refs #22564 [finc] use event.key instead of event.keyCode --- themes/finc/js/common-finc.js | 75 ++++++++++++++++--- .../finc/templates/Recommend/SideFacets.phtml | 2 +- themes/finc/templates/layout/layout.phtml | 4 +- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/themes/finc/js/common-finc.js b/themes/finc/js/common-finc.js index 3b80a9ac86a..033bc3db4de 100644 --- a/themes/finc/js/common-finc.js +++ b/themes/finc/js/common-finc.js @@ -8,27 +8,80 @@ function setupOffcanvas() { $('.close-offcanvas').focus(); // Set focus to the back button of the sidebar $('.sidebar .active').focus(); // Special case: account sidebar: set focus on the active element }); - } - // Handle sidebar in case of config.ini [Site] offcanvas=false configuration - if ($('.sidebar').length > 0 && !($(document.body).hasClass("offcanvas"))) { - $('[data-toggle="offcanvas"]').click(function offcanvasClick(e) { - e.preventDefault(); - window.location.href = '#myresearch-sidebar'; - $('.close-offcanvas').focus(); // Set focus to the back button of the sidebar - $('.sidebar .active').focus(); // Special case: account sidebar: set focus on the active element + + // Keep focus within sidebar on mobile + $('.sidebar').on('keydown', function (e) { + if (document.body.classList.contains('active') && $(document).width() <= 767) { + if (e.key === 'Escape') { // esc + $('.close-offcanvas').click(); + } + if (e.key === 'Tab') { // tab + retainFocus(e, this); + } + } }); + } + if ($('.sidebar').length > 0) { + // Handle sidebar in case of config.ini [Site] offcanvas=false configuration + if (!($(document.body).hasClass("offcanvas"))) { + $('[data-toggle="offcanvas"]').click(function offcanvasClick(e) { + e.preventDefault(); + window.location.href = '#myresearch-sidebar'; + $('.close-offcanvas').focus(); // Set focus to the back button of the sidebar + $('.sidebar .active').focus(); // Special case: account sidebar: set focus on the active element + }); + } + // Handle sidebar in case of config.ini [Site] offcanvas=false configuration - END + $('.close-offcanvas').click(function offcanvasClick(e) { - e.preventDefault(); - window.location.href = '#content'; + // Handle sidebar in case of config.ini [Site] offcanvas=false configuration + if (!($(document.body).hasClass("offcanvas"))) { + e.preventDefault(); + window.location.href = '#content'; + } $('.search-filter-toggle').focus(); // Set focus on the toggle button }); } } +/** + * Keyboard and focus controllers + * Copied from lightbox.js + */ +var FOCUSABLE_ELEMENTS = ['a[href]', 'area[href]', 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 'select:not([disabled]):not([aria-hidden])', 'textarea:not([disabled]):not([aria-hidden])', 'button:not([disabled]):not([aria-hidden])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex^="-"])']; +function getFocusableNodes (element) { + let nodes = element.querySelectorAll(FOCUSABLE_ELEMENTS); + return Array.apply(null, nodes); +} + +function retainFocus(event, panel) { + var focusableNodes = getFocusableNodes(panel); + + // no focusable nodes + if (focusableNodes.length === 0) + return; + + if (!panel.contains(document.activeElement)) { + focusableNodes[0].focus(); + } else { + var focusedItemIndex = focusableNodes.indexOf(document.activeElement); + + if (event.shiftKey && focusedItemIndex === 0) { + focusableNodes[focusableNodes.length - 1].focus(); + event.preventDefault(); + } + + if (!event.shiftKey && focusableNodes.length > 0 && focusedItemIndex === focusableNodes.length - 1) { + focusableNodes[0].focus(); + event.preventDefault(); + } + } +} + /* use css class 'skip-to' to jump to landmark - RL */ $(document).ready(function () { $(document).on('click enter',".skip-to", function (e) { - if (e.type === 'enter' && e.keyCode !== 13) { + if (e.type === 'enter' && e.key !== 'Enter') { return; } diff --git a/themes/finc/templates/Recommend/SideFacets.phtml b/themes/finc/templates/Recommend/SideFacets.phtml index 2f054bfd36f..571a5a3d95e 100644 --- a/themes/finc/templates/Recommend/SideFacets.phtml +++ b/themes/finc/templates/Recommend/SideFacets.phtml @@ -57,7 +57,7 @@ <div class="facet-group" id="side-panel-<?=$this->escapeHtmlAttr($title) ?>"> <?php /* finc adds h3 and aria coding; also uses a instead of button for W3C validation - #19695 */ ?> <h3> - <a <?php if (in_array($title, $collapsedFacets)): ?>class="title collapsed" aria-expanded="false"<?php else: ?>class="title" aria-expanded="true"<?php endif ?> data-toggle="collapse" href="#side-collapse-<?=$this->escapeHtmlAttr($title) ?>" > + <a <?php if (in_array($title, $collapsedFacets)): ?>class="title collapsed" aria-expanded="false"<?php else: ?>class="title" aria-expanded="true"<?php endif ?> id="control-for-side-collapse-<?=$this->escapeHtmlAttr($title)?>" data-toggle="collapse" href="#side-collapse-<?=$this->escapeHtmlAttr($title) ?>" > <?php /* finc: add span #19934 */ ?> <?=$this->transEsc($cluster['label'])?> <span class="sr-only"><?=$this->transEsc('facet_select_hint') ?></span> </a> diff --git a/themes/finc/templates/layout/layout.phtml b/themes/finc/templates/layout/layout.phtml index cd069a76a70..88bdc236b6a 100644 --- a/themes/finc/templates/layout/layout.phtml +++ b/themes/finc/templates/layout/layout.phtml @@ -215,9 +215,9 @@ if (!isset($this->layout()->searchbox)) { <?php endif; ?> <?php endforeach; ?> <?php elseif (strcmp($this->layout()->userLang, 'de') == 0): ?> - <a class="sr-only skip-to" href="#myresearch-sidebar"><?=$this->transEsc($this->overrideSideFacetCaption ?? 'Narrow Search')?></a> + <a class="sr-only skip-to hidden-xs" href="#control-for-side-collapse-facet_avail"><?=$this->transEsc($this->overrideSideFacetCaption ?? 'Narrow Search')?></a> <?php else: ?> - <a class="sr-only skip-to" href="#myresearch-sidebar"><?=$this->transEsc('skip-to')?><?=strtolower($this->transEsc($this->overrideSideFacetCaption ?? 'Narrow Search'))?></a> + <a class="sr-only skip-to hidden-xs" href="#control-for-side-collapse-facet_avail"><?=$this->transEsc('skip-to')?><?=strtolower($this->transEsc($this->overrideSideFacetCaption ?? 'Narrow Search'))?></a> <?php endif; ?> <?php endif; ?> </div> -- GitLab