From e336dddbfb7064d73fe44f87b5a34b0b28305d35 Mon Sep 17 00:00:00 2001 From: Martin Renvoize <martin.renvoize@ptfs-europe.com> Date: Tue, 9 Jun 2020 14:10:53 +0100 Subject: [PATCH] Bug 22807: Add 'Skip to content' option This patch adds a 'Skip to content' link to the header bar which will only appear upon the first use of 'tab' to navigate after any fresh page load in the OPAC. Test plan 1/ Load any page in the OPAC 2/ Hit the `tab` key 3/ Note the new 'Skip to main content' link appears at the top left of the screen. 4/ Hit `Enter` or Click the button 5/ Note the page scrolls to the area of the page that has the first block containing a .maincontent class. 6/ Note that the next available focusable element after the first .maincontent block has been given focus. 7/ Note that the link has been hidden --- .../bootstrap/en/includes/masthead.inc | 1 + koha-tmpl/opac-tmpl/bootstrap/js/global.js | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc index 88dd9a9255..8de7ec60a5 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc @@ -12,6 +12,7 @@ <div class="navbar navbar-inverse navbar-static-top"> <div class="navbar-inner"> <div class="container-fluid"> + <button id="scrolltocontent" class="sr-only sr-only-focusable pull-left nav btn btn-danger" type="button">Skip to main content</button> <h1 id="logo"> <a class="brand" href="/cgi-bin/koha/opac-main.pl"> [% IF ( LibraryNameTitle ) %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/global.js b/koha-tmpl/opac-tmpl/bootstrap/js/global.js index 76ce7b5cb0..5eb956b700 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/js/global.js +++ b/koha-tmpl/opac-tmpl/bootstrap/js/global.js @@ -91,3 +91,49 @@ function confirmModal(message, title, yes_label, no_label, callback) { $("#bootstrap-confirm-box-modal-cancel").text( no_label || 'Cancel' ); $("#bootstrap-confirm-box-modal").modal('show'); } + +//Add jQuery :focusable selector +(function($) { + function visible(element) { + return $.expr.filters.visible(element) && !$(element).parents().addBack().filter(function() { + return $.css(this, 'visibility') === 'hidden'; + }).length; + } + + function focusable(element, isTabIndexNotNaN) { + var map, mapName, img, nodeName = element.nodeName.toLowerCase(); + if ('area' === nodeName) { + map = element.parentNode; + mapName = map.name; + if (!element.href || !mapName || map.nodeName.toLowerCase() !== 'map') { + return false; + } + img = $('img[usemap=#' + mapName + ']')[0]; + return !!img && visible(img); + } + return (/input|select|textarea|button|object/.test(nodeName) ? + !element.disabled : + 'a' === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible(element); + } + + $.extend($.expr[':'], { + focusable: function(element) { + return focusable(element, !isNaN($.attr(element, 'tabindex'))); + } + }); +})(jQuery); + +$("#scrolltocontent").click(function() { + var content = $(".maincontent"); + if (content.length > 0) { + $('html,body').animate({ + scrollTop: content.first().offset().top + }, + 'slow'); + content.first().find(':focusable').eq(0).focus(); + } +}); -- 2.20.1