jQuery: Make submenu appear and disappear after a period of time - javascript

I'm trying to make a submenu which appears after some time. If it's already open I'd like other menus to pop up instantly on hover. However, on mouse leave it should stay open for a short time because the user could have moved the mouse accidentally outside the child-div.
Well, the problem is that it even opens (after the set time) if you hover it accidentally. This shouldn't happen.
Here's my code:
var timer = false;
$('li.mega-menu-dropdown').hover(function(e){
var el = this;
if ($("li.mega-menu-dropdown.open").length == 0)
{
setTimeout(function() {
openMenu(el);
}, 1000);
} else {
clearTimeout(timer);
openMenu(el);
}
},
function(){
timer = setTimeout(function(){
$('li.mega-menu-dropdown').removeClass('open');
},300);
});
function openMenu(el) {
$('li.mega-menu-dropdown').removeClass('open');
$(el).toggleClass("open");
}
Here's my jsfiddle: http://jsfiddle.net/bsnubner/
Edit:
Just hover it, stay there with the mouse and it'll work as expected. But then try to move the mouse over the "Hover Menu"-Link and instantly away of it. You'll see that it automatically opens the submenu even if you aren't in the menu anymore. Even worse: You have to go inside and outside the menu again to close it.
The problem will be, that on hover it sets the timeout with the function call. This will execute the function after the set time - even if you aren't in the menu anymore. But how could I prevent it?
I'd be very thankful if you could lead me on the right track.

Okay, my solution is as follows if you haven't a better one:
I have simply added:
var startTimer = false;
And kill the timer if the user accidentally hovered a menu link.
http://www.jsfiddle.net/bsnubner/4
If a user hovers "Hover Menu" it'll pop up after the timeout. If he then hovers "Hover Menu 2" and the other submenu is still opened, it'll open the second submenu instantly without delay.
If the user accidentally hovers one menu link only for a short time it won't open it's submenu.
Onmouseleave it closes as expected after some time :)

Related

Page jumps back to element scrolled into view if user scrolls immediately after

I am trying to create smooth scrolling when clicking certain anchor tags on my page. This is the on click event handler below.
const smoothScrollToView = (evt, id) => {
if (typeof window !== 'undefined') {
evt.preventDefault();
evt.stopPropagation();
const selectedNode = global.document.querySelector(`#${id}`);
if (!selectedNode) return evt;
selectedNode.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
global.window.history.pushState(null, null, `#${id}`);
}
return true;
};
It scrolls to element correctly; however, if the user should scroll immediately after the animation is done, the view jumps back to the element previously scrolled into view. If the user scrolls ~2 seconds after the animation, this behaviour does not occur. The only fix I have come across that makes it work without the jank is setting the href value of the a tag to javascript:void(0), and I would very much like to avoid that. Is there something wrong with my implementation, please?
I ended up using https://github.com/zengabor/zenscroll to implement the smooth scroll.

Cannot hide the windows with 2nd click

I click on the button in red rectangle to show the windows. Now, if want want to close the windows, i just click on other part of the grey bar. What I want to do is to modify the code to click the button in red rectangle 2nd time to close the windows, but it does not work.
I have put the html and related files here.
The main html is chat.html, where the main javascript lies in
assets\plugins\emojiarea\jquery.emojiarea.js
Following is portion of the code:
EmojiMenu.prototype.hide = function(callback) {
if (this.emojiarea) {
this.emojiarea.menu = null;
this.emojiarea.$button.removeClass('on');
this.emojiarea = null;
}
this.visible = false;
this.$menu.hide();
};
EmojiMenu.prototype.show = function(emojiarea) {
if (this.emojiarea && this.emojiarea === emojiarea) return;
this.emojiarea = emojiarea;
this.emojiarea.menu = this;
this.reposition();
this.$menu.show();
this.visible = true;
};
I try to use this.visible to detect the whether the windows has been opened, if yes, then close it, but it does not work out. Is there a possibility to make the windows closed when I click the button in red rectangle 2nd time?
So I went through the plugin. This piece of code:
$body.on('mouseup', function() {
self.hide();
});
is why you couldn't use this.visible to check if it was already open or not,because every time you click on the button too this mouseup is triggered effectively hiding and then showing the popup.
Right after this:$button.on('click', function(e) {
EmojiMenu.show(self);
e.stopPropagation();
});Add this:$button.on('mouseup', function(e) {
e.stopPropagation();
});This will prevent the bubbling of the mouseup event from the button itself.Now you can use "this.visible to detect the whether the windows has been opened, if yes, then close it."

Turn off function on mouseoff and mouseup

I have implemented my own scrolling, in a ticker with Jquery because the normal scrolling doesn't work too well when there's already css animation involved.
What I want to have happen is when you click and drag on the controller, which is a div that contains the ticker, the ticker moves. When you release the mouse button, it stops. No problem there. The problem comes in, when I don't release the mouse button, but I do take the mouse off of the controller. When this happens track_mouse_pos doesn't stop. So clicked or not when I put my mouse back on the controller I am scrolling.
$("#controller").mousedown(function (event) {
var start_x = event.clientX;
var start_y = event.clientY;
$("#controller").on('mousemove', {start_x: start_x}, track_mouse_pos);
});
$("#controller").mouseup(function () {
$("#controller").off('mousemove', track_mouse_pos);
});
How can I turn off ('mousemove', track_mouse_pos);? Is it ok to just have a .mouseup and .mouseoff line doing the same thing?
You need to check if the mouse button pressed in the "track_mouse_pos" function.
function track_mouse_pos(e){
if(e.which!=1) {$("#controller").trigger('mouseup');return}
...
}

Javascript onclick dropdown menu

I'm struggling with this javascript at the moment.
$(document).ready(function () {
var visible = false;
var body = false;
$("body").mouseup(function () {
if (visible) {
$(this).parent().find("ul.subnav").slideUp('slow');
visible = false;
$(this).removeClass("clicked-background");
body = true;
}
});
$("ul.topnav li a").click(function () { //When trigger is clicked...
var menu = $(this).parent().find('ul.subnav');
if (!visible && !body) {
$(this).parent().find("ul.subnav").slideDown('fast').show();
visible = true;
$(this).addClass("clicked-background");
}
// else if (visible)
//{
// $(this).parent().find("ul.subnav").slideUp('slow');
// visible = false;
// $(this).removeClass("clicked-background");
// }
body = false;
});
});
I wanted to add the feature, so if you clicked outside the menu/navigation the dropdown would hide.
The current problem with this code is, that if you click the menu and then click outside the menu - you have to double click the menu again to get it showen. This is caused by the body variable is set too 'True' ofc.
I made the body variable trying to fix the problem if you clicked the menu - and then clicked the same link again. The menu would first open correctly, and then close and open again.
Soo main problem is. My navigation open -> closes -> open
Don't use global variables. Check if the actual element is visible by checking
.is(':visible');
You can use that on the various selectors you have now.
I would be tempted to use onmouseout of the 'now visible' menu as the event of choice..
I dont think that running events off of the body tag is the good way to go.
the flow should be..
click (menu button or link)
show menu
set onmouseout for button and menu on click
onmouseout, remove onmouseout events

Google Chrome: Focus issue with the scrollbar

I am using jQuery 1.3.2.
There is an input field in a form.
Clicking on the input field opens a div as a dropdown. The div contains a list of items. As the list size is large there is a vertical scrollbar in the div.
To close the dropdown when clicked outside, there is a blur event on the input field.
Now the problem is:
In chrome(2.0.172) when we click on the scrollbar, the input field will loose focus.
And now if you click outside, then the dropdown won't close(as the input has already lost focus when you clicked on the srollbar)
In Firefox(3.5), IE(8), opera(9.64), safari() when we click on the scrollbar the input field will not loose focus. Hence when you click outside (after clicking on the srollbar) the dropdown will close. This is the expected behaviour.
So In chrome once the scrollbar is clicked, and then if I click outside the dropdown won't close.
How can i fix this issue with chrome.
Well, I had the same problem in my dropdown control. I've asked Chrome developers concerning this issue, they said it's a bug that is not going to be fixed in the nearest future because of "it has not been reported by many people and the fix is not trivial". So, let's face the truth: this bug will stay for another year at least.
Though, for this particular case (dropdown) there is a workaround. The trick is: when one click on a scrollbar the "mouse down" event comes to the owner element of that scrollbar. We can use this fact to set a flag and check it in "onblur" handler. Here the explanation:
<input id="search_ctrl">
<div id="dropdown_wrap" style="overflow:auto;max-height:30px">
<div id="dropdown_rows">
<span>row 1</span>
<span>row 2</span>
<span>row 2</span>
</div>
</div>
"dropdown_wrap" div will get a vertical scrollbar since its content doesn't fit fixed height. Once we get the click we are pretty sure that scrollbar was clicked and focus is going to be taken off. Now some code how to handle this:
search_ctrl.onfocus = function() {
search_has_focus = true
}
search_ctrl.onblur = function() {
search_has_focus = false
if (!keep_focus) {
// hide dropdown
} else {
keep_focus = false;
search_ctrl.focus();
}
}
dropdow_wrap.onclick = function() {
if (isChrome()) {
keep_focus = search_has_focus;
}
}
That's it. We don't need any hacks for FF so there is a check for browser. In Chrome we detect click on scrollbar, allow bluring focus without closing the list and then immediately restore focus back to input control. Of course, if we have some logic for "search_ctrl.onfocus" it should be modified as well. Note that we need to check if search_ctrl had focus to prevent troubles with double clicks.
You may guess that better idea could be canceling onblur event but this won't work in Chrome. Not sure if this is bug or feature.
P.S. "dropdown_wrap" should not have any paddings or borders, otherwise user could click in this areas and we'll treat this as a scrollbar click.
I couldn't get these answers to work, maybe because they are from 2009. I just dealt with this, I think ihsoft is on the right track but a bit heavy handed.
With two functions
onMouseDown() {
lastClickWasDropdown=true;
}
onBlur() {
if (lastClickWasDropdown) {
lastClickWasDropdown = false;
box.focus();
} else {
box.close();
}
}
The trick is in how you bind the elements. The onMouseDown event should be on the "container" div which contains everything that will be clicked (ie, the text box, the dropdown arrow, and the dropdown box and its scroll bar). The Blur event (or in jQuery the focusout event) should be bound directly to the textbox.
Tested and works!
I was facing the same situation/problem and I tested the solution from "ihsoft" but it has some issues. So I worked on an alternative for that and made just one similar to "ihsoft" but one that works. here is my solution:
var hide_dropdownlist=true;
search_ctrl.onblur = function() {
search_has_focus = false
if (hide_dropdownlist) {
// hide dropdown
} else {
hide_dropdownlist = true;
search_ctrl.focus();
}
}
dropdow_wrap.onmouseover = function() {
hide_dropdownlist=false;
}
dropdow_wrap.onmouseoout = function() {
hide_dropdownlist=true;
}
I hope this will help someone.
Earlier also I faced such situation and this is what I have been doing.
$('html').click(function() {
hasFocus = 0;
hideResults();
});
and on the input field i will do this
$('input').click()
{
event.stopPropagation();
}
So this will close the drop down if clicked anywhere outside the div (even the scrollbar).
But I thought if someone could provide a more logical solution.
Could you maybe set the blur event to fire on the drop down div as well? This way, when either the input or the drop down loses focus, it will dissapear...
I'm curious...
You're using the last version of every browser, why don't you try it in chrome 4.0.202?
instead of detecting the blur, detect the document.body or window click and grab the mouse point. determine if this mouse point is outside of the menu box. presto, you've detected when they clicked outside the box!
I solved this by doing the following:
#my_container is the container which has the "overflow: auto" CSS rule
$('#my_container')
.mouseenter(function(){
// alert('ctr in!');
mouse_in_container = true;
})
.mouseleave(function(){
// alert('ctr out!');
mouse_in_container = false;
});
And then:
$('input').blur(function(){
if(mouse_in_container)
return;
... Normal code for blur event ...
});
When I select an element in the drop down, I rewrite the code as:
(>> ADDED THIS) mouse_in_container=false;
$('input').attr('active', false); // to blur input
$('#my_container').hide();

Categories