353da0efd7a5e331086b109f5ea4a14c30854269 Merge parents 687677c1289 1b0a3eedc6f lrnassar Wed Mar 18 14:04:15 2026 -0700 Fix skip nav link appearing in hgc popups: use tabindex=-1 to prevent auto-focus, with JS in jquery.plugins.js to enable the link on first Tab keypress. Reverts :focus-visible approach which didn't work due to browser auto-focus being treated as keyboard focus. refs #37252 diff --cc src/hg/js/jquery.plugins.js index fcbeb81d373,fcbeb81d373..7633ff8631f --- src/hg/js/jquery.plugins.js +++ src/hg/js/jquery.plugins.js @@@ -1,261 -1,261 +1,270 @@@ /* JQuery Plugins + some code required for drop down menus * Must be loaded after jquery.js * * CONTENTS: * hoverIntent r5 * Superfish v1.4.8 - jQuery menu widget * Superfish initialization (Add Superfish to all Nice menus with some basic options.) */ /** * hoverIntent r5 // 2007.03.27 // jQuery 1.1.2+ * * * hoverIntent is currently available for use in all personal or commercial * projects under both MIT and GPL licenses. This means that you can choose * the license that best suits your project, and use it accordingly. * @param f onMouseOver function || An object with configuration options * @param g onMouseOut function || Nothing (use configuration options object) * @author Brian Cherne */ (function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY;};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY)) »'].join('')), over = function(){ var $$ = $(this), menu = getMenu($$); clearTimeout(menu.sfTimer); $$.showSuperfishUl().siblings().hideSuperfishUl(); }, out = function(){ var $$ = $(this), menu = getMenu($$), o = sf.op; clearTimeout(menu.sfTimer); menu.sfTimer=setTimeout(function(){ o.retainPath=($.inArray($$[0],o.$path)>-1); $$.hideSuperfishUl(); if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);} },o.delay); }, getMenu = function($menu){ var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0]; sf.op = sf.o[menu.serial]; return menu; }, addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); }; return this.each(function() { var s = this.serial = sf.o.length; var o = $.extend({},sf.defaults,op); o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){ $(this).addClass([o.hoverClass,c.bcClass].join(' ')) .filter('li:has(ul)').removeClass(o.pathClass); }); sf.o[s] = sf.op = o; $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() { if (o.autoArrows) addArrow( $('>a:first-child',this) ); }) .not('.'+c.bcClass) .hideSuperfishUl(); var $a = $('a',this); $a.each(function(i){ var $li = $a.eq(i).parents('li'); $a.eq(i).on("focus", function(){over.call($li);}).on("blur", function(){out.call($li);}); }); o.onInit.call(this); }).each(function() { var menuClasses = [c.menuClass]; if (sf.op.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass); $(this).addClass(menuClasses.join(' ')); }); }; var sf = $.fn.superfish; sf.o = []; sf.op = {}; sf.c = { bcClass : 'sf-breadcrumb', menuClass : 'sf-js-enabled', anchorClass : 'sf-with-ul', arrowClass : 'sf-sub-indicator', shadowClass : 'sf-shadow' }; sf.defaults = { hoverClass : 'sfHover', pathClass : 'overideThisToUse', pathLevels : 1, delay : 800, animation : {opacity:'show'}, speed : 'normal', autoArrows : true, dropShadows : true, disableHI : false, // true disables hoverIntent detection onInit : function(){}, // callback functions onBeforeShow: function(){}, onShow : function(){}, onHide : function(){} }; $.fn.extend({ hideSuperfishUl : function(){ var o = sf.op, not = (o.retainPath===true) ? o.$path : ''; o.retainPath = false; var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass) .find('>ul').hide().css('visibility','hidden'); o.onHide.call($ul); return this; }, showSuperfishUl : function(){ var o = sf.op, sh = sf.c.shadowClass+'-off', $ul = this.addClass(o.hoverClass) .find('>ul:hidden').css('visibility','visible'); o.onBeforeShow.call($ul); $ul.animate(o.animation,o.speed,function(){ o.onShow.call($ul); }); return this; } }); })(jQuery); // This uses Superfish 1.4.8 // (http://users.tpg.com.au/j_birch/plugins/superfish) // Add Superfish to all Nice menus with some basic options. (function ($) { $(document).ready(function() { $('ul.nice-menu').superfish({ // Apply a generic hover class. hoverClass: 'over', // Disable generation of arrow mark-up. autoArrows: false, // Disable drop shadows. dropShadows: false, // Mouse delay. delay: 800, // Animation speed. speed: 1 }); $('ul.nice-menu ul').css('display', 'none'); }); })(jQuery); // Keyboard accessibility for menu bar disclosure buttons (WCAG 2.1) (function ($) { $(document).ready(function() { ++ // Enable skip nav link on first Tab keypress (starts with tabindex=-1 to prevent ++ // auto-focus in popup windows like hgc from making it visible) ++ $(document).one('keydown', function(e) { ++ if (e.key === 'Tab') { ++ var $skip = $('a.skipNav'); ++ if ($skip.length) $skip.removeAttr('tabindex'); ++ } ++ }); ++ var $menu = $('ul.nice-menu'); if (!$menu.length) return; var suppressFocus = false; // prevent focus handler from interfering with click/escape // Track mouse clicks so focus handler can distinguish Tab from click $menu.on('mousedown', 'li.menuparent > button', function() { suppressFocus = true; }); // Toggle dropdown when a disclosure button is clicked (Enter/Space/click) $menu.on('click', 'li.menuparent > button', function(e) { e.preventDefault(); suppressFocus = false; var $li = $(this).parent(); var isOpen = $li.hasClass('over'); // Close all open menus first $menu.find('li.menuparent').removeClass('over') .find('> ul').hide().css('visibility', 'hidden'); $menu.find('li.menuparent > button, li.menuparent > a') .attr('aria-expanded', 'false'); if (!isOpen) { $li.addClass('over').find('> ul').show().css('visibility', 'visible'); $(this).attr('aria-expanded', 'true'); } }); // Focus on a button shows its dropdown (Tab navigation only, not mouse click) $menu.on('focus', 'li.menuparent > button', function() { if (suppressFocus) { suppressFocus = false; return; } var $li = $(this).parent(); $li.showSuperfishUl().siblings().hideSuperfishUl(); $(this).attr('aria-expanded', 'true'); $li.siblings().find('> button, > a').attr('aria-expanded', 'false'); }); $menu.on('blur', 'li.menuparent > button', function() { var $li = $(this).parent(); var o = $.fn.superfish.op; var delay = (o && o.delay) ? o.delay : 800; var menu = $menu[0]; clearTimeout(menu.sfTimer); var $btn = $(this); menu.sfTimer = setTimeout(function() { $li.hideSuperfishUl(); $btn.attr('aria-expanded', 'false'); }, delay); }); // Sync aria-expanded for -based parent items (Genomes, Genome Browser) $menu.on('focus', 'li.menuparent > a[aria-expanded]', function() { $(this).attr('aria-expanded', 'true'); }); $menu.on('blur', 'li.menuparent > a[aria-expanded]', function() { var $a = $(this); setTimeout(function() { if (!$a.parent().hasClass('over')) { $a.attr('aria-expanded', 'false'); } }, 900); }); // Sync aria-expanded on mouse hover for all parent items $menu.on('mouseenter', 'li.menuparent', function() { $(this).find('> button, > a[aria-expanded]').attr('aria-expanded', 'true'); }); $menu.on('mouseleave', 'li.menuparent', function() { var $trigger = $(this).find('> button, > a[aria-expanded]'); var o = $.fn.superfish.op; var delay = (o && o.delay) ? o.delay : 800; setTimeout(function() { if (!$trigger.parent().hasClass('over')) { $trigger.attr('aria-expanded', 'false'); } }, delay + 100); }); // Escape key closes any open dropdown and returns focus to its trigger $(document).on('keydown', function(e) { if (e.key === 'Escape' || e.keyCode === 27) { var $openLi = $menu.find('li.menuparent.over'); if ($openLi.length) { $openLi.removeClass('over').find('> ul').hide().css('visibility', 'hidden'); var $trigger = $openLi.find('> button, > a').first(); $trigger.attr('aria-expanded', 'false'); suppressFocus = true; // prevent focus handler from re-opening $trigger.focus(); e.stopPropagation(); } } }); }); })(jQuery);