Javascript conflicts with Bootstrap functionality - javascript
I'm building a site that contains a Bootstrap Nav Tab section. The problem is my dev team is implementing an accessibility javascript that conflicts with Bootstrap. I am attaching a link to a codepen showing the problem. (See Below). Which its basically the nav tabs simply do not work. No click event is happening.
I don't have much experience with accessibility scripting but I am hoping someone here does and can tell me how to make bootstrap work without losing the functionality this accessibility script provides.
The script is designed to allow non-sighted users using screen readers (i.e. JAWS) to be able to tab around the menus and screen items based on what JAWS is telling them by reading the ARIAS and navigating through ROLES.
The Javascript is as follows:
$(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();
});
}
The HTML is in the pen link attached for the sake of not cluttering this question. Besides, you'll be able to test it there better.
CODEPEN DEMO HERE
p.s. Also, I am using a small Bootstrap accordion within one of the Tabs. (Not shown in the demo for simplicity purposes). So if you think of a fix that can globally fix all Bootstrap functionality rather than the navtabs only, I'll appreciate it even more, but I am not expecting it.
Thanks in advance
The problem is with this event handler at the very end of the code in the CodePen:
$(this).click(function(e){
e.stopPropagation();
});
That's explicitly preventing clicks on the menu tabs from bubbling up to any other event handler. Probably the Bootstrap tab code binds its event handlers at the top of the DOM.
It's not clear what the intention of that code is; it's not commented and it's not apparent from looking at the rest of the code. It may be just a gratuitous addition, in which case it's erroneous given the nature of that code.
Related
Capture the event click of "Open Link in New Tab" javascript or jquery - Cloaking URL
I know that I can capture the events of click: left, right and middle button by: contextmenu e.which But, I need to capture the event click of "Open Link in New Tab": When you do right click in a link, it shows a menu with the option "Open Link in New Tab". How can I capture that event ? PD: is not the right click event, is the event when you do click in "Open Link in New Tab". The main reason is, I'm trying to cloak links for affiliated sites, but when I do right click and choose the option "Open Link in New Tab", not working, it doesn't show me the real hidden url. I found the script searching in google but I edited the script to my needs, but I have the problem that I told above. The code: (function ($) { ninja_href(".ninja-href"); function ninja_href_call(e,which) { var ninja_url = e.target.getAttribute('data-ninja-url'); var ninja_target = e.target.getAttribute('data-ninja-target'); if(ninja_target == null || typeof ninja_target == undefined || which === 3) { ninja_target = "_self"; } if(which === 2) { ninja_target = "_blank"; } var win = window.open(ninja_url, ninja_target); if (win && ninja_target == "_blank") { win.focus(); } } function ninja_href(element) { if(element == null || typeof element == undefined){ element = ".ninja-href"; } if (document.addEventListener) { document.addEventListener('click', function(e) { if(e.target && e.target.matches(element)) { if (e.which === 1 || e.which === 2) { e.preventDefault(); ninja_href_call(e,e.which); } } }, false); document.addEventListener('mousedown', function(e) { if(e.target && e.target.matches(element)) { if (e.which === 2) { e.preventDefault(); ninja_href_call(e,e.which); } } }, false); document.addEventListener('contextmenu', function(e) { console.warn(e); if(e.target && e.target.matches(element)) { } }, false); } else { document.attachEvent('click', function() { if(e.target && e.target.matches(element)) { if (e.which === 1 || e.which === 2) { e.preventDefault(); ninja_href_call(e,e.which); } } }); } } }(window.jQuery)); Any idea
Please take a look below... This is how you can handle it. <script type='text/javascript'> jQuery(function($){ $('a').mousedown(function(event) { switch (event.which) { case 1: //alert('Left mouse button pressed'); $(this).attr('target','_self'); break; case 2: //alert('Middle mouse button pressed'); $(this).attr('target','_blank'); break; case 3: //alert('Right mouse button pressed'); $(this).attr('target','_blank'); break; default: //alert('You have a strange mouse'); $(this).attr('target','_self"'); } }); });
Can't call angular ng-click from jQuery
Im trying to call ng-click from jQuery but cant get it work. Can someone tell me how to do it properly? HTML: <a ng-click="changeData()">Testing</a> <a ng-click="changeData()">Testing 2</a> <a ng-click="changeData()">Testing 3</a> jQuery: $(document).keydown(function(e){ if (checkNav && checkNav()) return; if (e.keyCode == 37) { // left setCurrent(x,y-1); e.preventDefault(); } else if (e.keyCode == 38) { // up setCurrent(x-1,y); e.preventDefault(); } else if (e.keyCode == 39) { // right setCurrent(x,y+1); e.preventDefault(); } else if (e.keyCode == 40) { // down setCurrent(x+1,y); e.preventDefault(); } else if (e.keyCode == 13) { $('a[ng-click="changeData()"]') } }); I want it to call same function as ng-click when clicking enter. It works fine if I have the following code for hrefs when clicking enter: } else if (e.keyCode == 13) { window.location = current.attr('href'); e.preventDefault(); } Thanks!
I think you mean you want something like this. Let me know if this is your intent or not: index.html <input ng-keyup="keyFn(event=$event)" ngclick="clickFn()">click</input> controller.js angular.module('myApp') .controller('myCtrl', function($scope) { $scope.keyFn = function(event){ if (event.keyCode && event.keyCode === 13/*enter key*/){ someFunction(); } }; $scope.clickFn = function(){ someFunction(); } }); function someFunction(){ console.log("event fired"); //functionality shared between click and `enter` keypress }
$('a[ng-click="changeData()"]') just fetches the element. If you want to trigger a click you need to call .click() like so $('a[ng-click="changeData()"]').click(); But I prefer thomas' answer that doesn't use jQuery at all, I don't see why you'd need it. Seems completely unnecessary for this.
iOS Spinning Wheel HTML5
I'm working on a webapp that will be used on iOS devices as well as Desktops (without touch). We are using a bootstrap to make the site as responsive as possible. We want to incoperate the spinning wheel known in iOS. We will style it differently but not the functionality. After some searching I came across this site: http://cubiq.org/spinning-wheel However this script only seems to work on touch capable devices. Would it be possible to edit the script so it will work on desktops too? I found this in the script can I add a mouseClickHandler here? handleEvent: function (e) { console.log(e.type); if (e.type == 'touchstart') { this.lockScreen(e); if (e.currentTarget.id == 'sw-cancel' || e.currentTarget.id == 'sw-done') { this.tapDown(e); } else if (e.currentTarget.id == 'sw-frame') { this.scrollStart(e); } } else if (e.type == 'touchmove') { this.lockScreen(e); if (e.currentTarget.id == 'sw-cancel' || e.currentTarget.id == 'sw-done') { this.tapCancel(e); } else if (e.currentTarget.id == 'sw-frame') { this.scrollMove(e); } } else if (e.type == 'touchend') { if (e.currentTarget.id == 'sw-cancel' || e.currentTarget.id == 'sw-done') { this.tapUp(e); } else if (e.currentTarget.id == 'sw-frame') { this.scrollEnd(e); } } else if (e.type == 'webkitTransitionEnd') { if (e.target.id == 'sw-wrapper') { this.destroy(); } else { this.backWithinBoundaries(e); } } else if (e.type == 'orientationchange') { this.onOrientationChange(e); } else if (e.type == 'scroll') { this.onScroll(e); } },
You could try using drag events, but they aren't supported well. Check out this MDN article and this one with more explanation on the events. You could also try using jQuery with for instance this plugin. Good luck!
jquery problems on click()
<script type="text/javascript"> $(document).ready(function(){ $("input[name='trim']").click(function (event) { if ($(this).val() == "deluxe") { $("input[name='option']").attr("checked", true); } else if ($(this).val() == "plain") { $("input[name='option']").attr("checked", false); } }); $("input[name='option']").click(function(event){ $("#custom").attr("checked","checked"); }); }); </script> This is radio and click button problem. First I click deluxe button, check button works fine. Then I click plain button it works fine too. Then I re-click deluxe button, check button won't working. Then I try to test out custom button. It not working either after I click plain button. Does anyone know whats going on? By the way plain works fine from beginning.
You should use jQuery prop() instead of attr(). attr() is buggy.
Use the following code which is a great jQuery extension. It will accept 1,0,'1','0',true,false, and unidentified. To see in action see my fiddle I posted your usage as well. (function( $ ) { $.fn.checked = function(value) { if(value === true || value === false) { // Set the value of the checkbox $(this).each(function(){ this.checked = value; }); } else if(value === undefined || value === 'toggle') { // Toggle the checkbox $(this).each(function(){ this.checked = !this.checked; }); } else if(value === 1 || value === '1') { $(this).each(function(){ this.checked = true; }); } else if(value === 0 || value === '0') { $(this).each(function(){ this.checked = false; }); } return this; }; })( jQuery ); Your usage would be like so: $("input[name='trim']").click(function (event) { if ($(this).val() == "deluxe") { $("input[name='option']").checked(1); } else if ($(this).val() == "plain") { $("input[name='option']").checked(0); } }); $("input[name='option']").click(function(event){ $("#custom").checked(1); });
mouse : disable right and middle button click
I've used this but it doesn't work; no errors in the firebug: $("div").live('mousedown', function(e) { if( (e.which == 1) ) { return ; }if( (e.which == 3) ) { return false; }else if( (e.which == 2) ) { return false; } }) I can disable right click with contextmenu but I dont know what to do about middle button.
You can do so with Javascript and/or an HTML attribute (which is really a Javascript event handler anyway) as described here <script language="javascript"> document.onmousedown=disableclick; status="Right Click Disabled"; function disableclick(e) { if (e.button == 2) { alert(status); return false; } } </script> and <body oncontextmenu="return false"> ... </body> That being said: DON'T DO IT. Why? Because it achieves nothing other than annoying users. Also many browsers have a security option to disallow disabling of the right click (context) menu anyway. Not sure why you'd want to. If it's out of some misplaced belief that you can protect your source code or images that way, think again: you can't.
You missed an 'else' in your code. $("div").live('mousedown', function(e) { if( (e.which == 1) ) { return ; }else if( (e.which == 3) ) { return false; }else if( (e.which == 2) ) { return false; } })