I have an issue with mouseleave and hover on devices that supports both Pointer and Touch events. These devices include laptops with a mouse and touchscreen.
I basically just want to disable mouseleave and hover, but the problem is it is a device that supports both and I can't find an article explaining this properly and there are no standards.
I had a look at the following links:
Disable hover effects on mobile browsers
How to remove/ignore :hover css style on touch devices
jquery preventing hover function on touch
jQuery mouseleave for touch screen / tablets
Disable hover effects on mobile browsers
We are using DNN (DotNetNuke) as a Content Management system. I know that you can build custom menu's using tokens and DDR menu's, but this is too complex for what I want to achieve.
My simple approach was to build the sub-menu from data fetched from our ERP database and display it when you hover over a DNN page link which is "disabled" with a certain name that matches using jQuery.
Everything works fine on a Desktop Device. It also works with a Touch & Pointer device using Chrome.
I am having an issue with Edge on a Tablet Device with Touch and Pointer events. The onmouseleave is fired when you tap on "Categories" which will cause the sub-menu to close. When you tap on the "Categories" menu, it fires the hover event.
What makes it more difficult is that the Sub-menu is not a direct child of the parent, so it is not always easy to use CSS selectors. Currently I place the module beneath the menu so that it is at least very close so that I can use Absolute and Relative positioning to get the sub-menu to display directly below the links. This is where you will notice that I have added a timeout function on the one mouseleave event to allow someone to navigate to the sub-menu when their mouse leaves the hover event.
Here is a screenshot of the menu. It contains sub categories which can show, but I just want to get the main menu showing properly on devices with both Touch and Point event support.
Example JSFidle Code
JSFidle: https://jsfiddle.net/Tig7r/e6k9cfj1/13/
HTML
<nav class="NavMenu">
<ul class="ul_menu">
<li class='item'><a href="#"><span>Home</span></a></li>
<li class='item'><a><span>Categories</span></a></li>
</ul>
</nav>
<div class="subLevel MegaMenuDiv" id="MegaMenuDiv">
<div class="custom_megamenu_wrapper">
<ul class="main-category-list has-children"><li><a href="javascript:void(0)" class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" style="">Accessories</a>
<ul class="secondary-items">
<li><a href="https://www.google.com" class="MegaMenu_Child_Link" style="">Accessory Holders</a></li>
<li><a href="https://www.google.com" class="MegaMenu_Child_Link" style="">Whiteboard Starter Pack</a></li>
</ul></li>
</ul>
</div>
</div>
css
.NavMenu{
width:100%;
height:40px;
background-color:red;
color:white !important;
}
.NavMenu ul li{
list-style:none;
display:inline-block;
padding:10px;
}
.ul_menu li a:link{
color:white;
}
.ul_menu li a:hover{
color:black;
}
#MegaMenuDiv{
background:black;
color:white;
position:absolute;
width:550px;
display:none;
min-height:300px;
}
.MegaMenuDiv a:link{
color:white;
}
.displayHiddenMenu{
display: block !important;
}
.main-category-list li{
list-style:none;
}
.secondary-items{
background: #31383e;
position: absolute;
top: 0;
left: 150px;
width: calc(80vw - 50%);
height: auto;
list-style: none;
/* padding: 20px; */
display: none;
height: 92%;
overflow-y: auto;
padding-top: 0px;
z-index: 1000;
max-width: 840px;
padding-top: 13px;
line-height: 2;
}
.secondary-items a:link, .secondary-items a:visited{
color:white !important;
}
JQUERY
$(document).ready(function () {
$(".item:contains(Categories)").hover(function () {
if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
} else {
console.log('No class, adding class');
$('.MegaMenuDiv').addClass("displayHiddenMenu");
}
});
/* Removes the submenu when the mouse moves away from categories */
$('.item:contains(Categories)').on("mouseleave", function (event) {
if ($('.MegaMenuDiv:hover').length > 0) {
// do nothing
} else {
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
}
});
$(".item:contains(Categories)").hover(function () {
if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
console.log('Item has class');
} else {
console.log('No class, adding class');
$('.MegaMenuDiv').addClass("displayHiddenMenu");
}
});
$(".item:contains(Categories)").on("touchstart click", function () {
if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
} else {
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
$('.MegaMenuDiv').addClass("displayHiddenMenu");
}
});
$('.MegaMenuDiv').on("mouseleave", function () {
console.log('Mouseleave remove class');
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
});
//Code for child menu elements
$('.MegaMenuLinkMainWithChildren').hover(function () {
if ($(this).next().hasClass('displayHiddenMenu')) {
//do nothing
} else {
$('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
$(this).next().addClass('displayHiddenMenu');
}
});
$('.MegaMenuLinkMainWithChildren').on('touchstart click', function () {
var secondaryitems = $(this).next();
if ($(secondaryitems).hasClass('displayHiddenMenu')) {
} else {
$('.MegaMenuLinkMainWithChildren').next().not(secondaryitems).removeClass('displayHiddenMenu');
$(secondaryitems).addClass("displayHiddenMenu");
}
});
});
I have played around with some of the code and managed to get it to work. The mouseleave and hover event wont be fired on Touch Devices which makes it work.
$(document).ready(function () {
var touched = false;
$(".item:contains(Categories)").on("mouseenter click", function (e) {
if (!touched) {
e.type == 'click' ? $('.MegaMenuDiv').toggleClass("displayHiddenMenu") : $('.MegaMenuDiv').addClass("displayHiddenMenu");
}
}).on('touchstart', function (e) {
touched = true;
setTimeout(function () {
touched = false;
}, 300);
// do touchstart stuff (similar to click or not)
// toggle MegaMenuDiv on click
if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
} else {
$('.MegaMenuDiv').addClass("displayHiddenMenu");
}
});
$('.MegaMenuDiv').on("mouseleave", function () {
if (!touched) {
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
}
});
// MegaMenuLinkMainWithChildren - Show children items
$(".MegaMenuLinkMainWithChildren").on('mouseenter touchstart click', function () {
// toggle MegaMenuDiv
$('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
$(this).next().addClass('displayHiddenMenu');
});
//Removes the sub-menu when hovering over other menu items
$('.item').not(".item:contains(Categories)").hover(function () {
console.log('Hovering over other items, remove class');
if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
$('.MegaMenuDiv').removeClass("displayHiddenMenu");
}
});
//Add a cursor the the pointer
$(".item:contains(Categories)").css("cursor", "pointer");
});
Here is the latest fiddle: https://jsfiddle.net/Tig7r/htLny8a7/1/