Javascript与Bootstrap功能冲突

时间:2015-01-10 21:49:42

标签: javascript jquery accessibility

我正在构建一个包含Bootstrap Nav Tab部分的站点。问题是我的开发团队正在实现与Bootstrap冲突的可访问性javascript。我附加了一个显示问题的codepen的链接。 (见下文)。其基本上导航标签根本不起作用。没有发生点击事件。

我在使用辅助功能脚本方面没有太多经验,但我希望有人在这里做,并且可以告诉我如何在不失去此辅助功能脚本提供的功能的情况下进行自举工作。

该脚本旨在允许使用屏幕阅读器(即JAWS)的无视用户能够根据JAWS通过读取ARIAS并通过ROLES导航来告诉他们的菜单和屏幕项目。

Javascript如下:

$(function(){
    $('.nav').setup_navigation();
});
var keyCodeMap = {
   48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9", 59:";",
65:"a", 66:"b", 67:"c", 68:"d", 69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l",
77:"m", 78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v", 87:"w", 88:"x", 89:"y", 90:"z",
96:"0", 97:"1", 98:"2", 99:"3", 100:"4", 101:"5", 102:"6", 103:"7", 104:"8", 105:"9"
} 


$.fn.setup_navigation = function(settings) {
    settings = jQuery.extend({
        menuHoverClass: 'main-menu-item',
    }, settings
);

// Add ARIA role to menubar and menu items
$(this).attr('role', 'menubar').find('li').attr('role', 'menuitem');
var top_level_links = $(this).find('> li > a');

//// Set tabIndex to -1 so that top_level_links can't receive focus until menu is open
//$(top_level_links).next('ul')
//.attr({ 'aria-hidden': 'true', 'role': 'menu' })
//.find('a');    


// Adding aria-haspopup for appropriate items

$(top_level_links).each(function(){
    if($(this).next('ul').length > 0)
        $(this).parent('li').attr('aria-haspopup', 'true');
});
$(top_level_links).each(function(){
    if($(this).next('ul').length > 0)
        $(this).parent('ul').attr('aria-haspopup', 'true');
});


$(top_level_links).hover(function(){
    $(this).closest('ul')
        .attr('aria-hidden', 'false')
        .find('.'+settings.menuHoverClass)
        .attr('aria-hidden', 'true')
        .removeClass(settings.menuHoverClass)
        .find('a')
        //.attr('tabIndex',-1);


$(this).next('ul')
    .attr('aria-hidden', 'false')
    .addClass(settings.menuHoverClass)
    .find('a').attr('tabIndex',0);
});


$(top_level_links).focus(function(){
    $(this).closest('ul')
        .attr('aria-hidden', 'false')
        .find('.'+settings.menuHoverClass)
        .attr('aria-hidden', 'true')
        .removeClass(settings.menuHoverClass)
        .find('a')
        //.attr('tabIndex',1);
    $(this).next('ul')
        .attr('aria-hidden', 'false')
        .addClass(settings.menuHoverClass)
        .find('a').attr('tabIndex',0);
});


// Bind arrow keys for navigation
$(top_level_links).keydown(function(e){
    if(e.keyCode == 37) {
        e.preventDefault();
        // This is the first item
        if($(this).parent('li').prev('li').length == 0) {
            $(this).parents('ul').find('> li').last().find('a').first().focus();
        } else {
            $(this).parent('li').prev('li').find('a').first().focus();
        }
    } else if(e.keyCode == 38) {
        e.preventDefault();
        if($(this).parent('li').find('ul').length > 0) {
            $(this).parent('li').find('ul')
            .attr('aria-hidden', 'false')
            .addClass(settings.menuHoverClass)
            .find('a').attr('tabIndex',0)
            .last().focus();
        }
    } else if(e.keyCode == 39) {
        e.preventDefault();
        // This is the last item
        if($(this).parent('li').next('li').length == 0) {
            $(this).parents('ul').find('> li').first().find('a').first().focus();
        } else {
            $(this).parent('li').next('li').find('a').first().focus();
        }
    } else if(e.keyCode == 40) {
        e.preventDefault();
        if($(this).parent('li').find('ul').length > 0) {
            $(this).parent('li').find('ul')
            .attr('aria-hidden', 'false')
            .addClass(settings.menuHoverClass)
            .find('a').attr('tabIndex',0)
            .first().focus();
        }
    } else if(e.keyCode == 13 || e.keyCode == 32) {
    // If submenu is hidden, open it
    //e.preventDefault();
    $(this).parent('li').find('ul[aria-hidden=true]')
        .attr('aria-hidden', 'false')
        .addClass(settings.menuHoverClass)
        .find('a').attr('tabIndex',0)
        .first().focus();
    } else if(e.keyCode == 27) {
        e.preventDefault();
        $('.'+settings.menuHoverClass)
        .attr('aria-hidden', 'true')
        .removeClass(settings.menuHoverClass)
        .find('a')
        //.attr('tabIndex',-1);
    } else {
        $(this).parent('li').find('ul[aria-hidden=false] a').each(function(){
            if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
            $(this).focus();
            return false;
            }
        });
    }
});

var links = $(top_level_links).parent('li').find('ul').find('a');

$(links).keydown(function(e){
    if(e.keyCode == 38) {
        e.preventDefault();
        // This is the first item
        if($(this).parent('li').prev('li').length == 0) {
            $(this).parents('ul').parents('li').find('a').first().focus();
        } else {
            $(this).parent('li').prev('li').find('a').first().focus();
        }
    } else if(e.keyCode == 40) {
        e.preventDefault();
        if($(this).parent('li').next('li').length == 0) {
            $(this).parents('ul').parents('li').find('a').first().focus();
        } else {
            $(this).parent('li').next('li').find('a').first().focus();
        }
    } else if(e.keyCode == 27 || e.keyCode == 37) {
        e.preventDefault();
        $(this)
        .parents('ul').first()
        .prev('a').focus()
        .parents('ul').first().find('.'+settings.menuHoverClass)
        .attr('aria-hidden', 'true')
        .removeClass(settings.menuHoverClass)
        .find('a')
        //.attr('tabIndex',-1);
    } else if(e.keyCode == 32) {
        e.preventDefault();
        window.location = $(this).attr('href');
    } else {
        var found = false;
        $(this).parent('li').nextAll('li').find('a').each(function(){
            if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
                $(this).focus();
                found = true;
                return false;
            }
        });

        if(!found) {
            $(this).parent('li').prevAll('li').find('a').each(function(){
                if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
                    $(this).focus();
                    return false;
                }
            });
        }
    }
});


 //Hide menu if click or focus occurs outside of navigation
$(this).find('a').last().keydown(function(e){
    if(e.keyCode == 9) {
        // If the user tabs out of the navigation hide all menus
        $('.'+settings.menuHoverClass)
        .attr('aria-hidden', 'true')
        .removeClass(settings.menuHoverClass)
        .find('a')
        //.attr('tabIndex',-1);
    }
});


$(document).click(function () {
    $('.' + settings.menuHoverClass).attr('aria-hidden', 'true').removeClass(settings.menuHoverClass).find('a').attr('tabIndex', 0);
});

$(this).click(function(e){
    e.stopPropagation();
});
}

为了不弄乱这个问题,HTML附在笔链中。此外,您还可以更好地测试它。

CODEPEN DEMO HERE

P.S。另外,我在其中一个标签中使用了一个小型Bootstrap手风琴。 (为简单起见,未在演示中显示)。因此,如果您想到一个可以全局修复所有Bootstrap功能而不仅仅是navtabs的修复程序,我会更加欣赏它,但我并不期待它。

提前致谢

1 个答案:

答案 0 :(得分:2)

问题在于CodePen代码最后的事件处理程序:

$(this).click(function(e){
    e.stopPropagation();
});

明确阻止菜单选项卡上的点击冒泡到任何其他事件处理程序。可能Bootstrap选项卡代码将其事件处理程序绑定在DOM的顶部。

目前尚不清楚该代码的意图是什么;它没有被评论,并且通过查看其余代码并不明显。它可能只是一个无偿的补充,在这种情况下,鉴于该代码的性质,它是错误的。