How to abort fading out of jqueryui menu? - javascript

I want to stop the fading out of a JQueryUI menu.
Same context: FireFox 43, Linux/Debian/Sid, Jquery2.2, JqueryUI1.11.4, as for this question; the alpha-stage MELT monitor, GPL free software on Linux/Debian with recent Firefox 38 or 43 on Linux; this is commit b505eccc1... on github
(JsFiddle MVCE example at end of question)
In my file webroot/nanoedit.js I hve a global variable mom_menucmdel which hold a JqueryUI menu (a dropdown menu). The mom_removecmdmenu function is clearing that global and removing that menu from the DOM.
I want this menu to fade out and be removed in a bit more than 9 seconds, if the user don't do any interaction. But if the user is moving the mouse inside the menu, I want the fading to abort. So I coded:
var curmenu = mom_menucmdel;
curmenu.mousemove
(function(ev)
{ console.log("momdelayrepl movefinishing ev=", ev, " curmenu=", curmenu);
curmenu.finish();
});
setTimeout(function()
{
console.log("mom_cmdkeypress-delayedreplmenudestroy curmenu=",
curmenu);
curmenu.delay(100).fadeOut(800+75*dollvalseq.length,
function () {
console.log ("momdelayrepl finalfaderemove curmenu=", curmenu);
mom_removecmdmenu();
});
}, 9500);
near line 427 of that nanoedit.js; my understanding is that finish would abort animations. But it does not work. The fading remains, and the menu disappears, even after mouse movements.
If you are brave enough to compile the MELT monitor, browse http://localhost.localdomain:8086/nanoedit.html, type $ e in the textearea, then the esc key.
JsFiddle example (MVCE)
See this JsFiddle which is a simplified variant of above; run it twice. First, click on the button and wait 10 seconds at least. The menu is fading out and disappears. Then, run it again, click on the button, and move the mouse inside the menu (perhaps even selecting some item), the menu still disappears in about 10 seconds but I want it to stay, perhaps indefinitely (in my nanoedit.js code the select function would remove it, in this JsFiddle I don't care)!

var mymenu;
var mybutton;
var count = 0;
var menuTO;
function remove_menu() {
if (!mymenu) return;
console.log("removing mymenu=", mymenu);
mymenu.remove();
}
function fadeOutMenu() {
console.log("fading mymenu=", mymenu);
mymenu.delay(100).fadeOut(900, remove_menu);
}
$(document).ready(function() {
mybutton = $("#mybutton_id");
mybutton.on("click", function() {
count++;
var menuid = "menuid_" + count;
$("#mymenudiv_id").append("<ul class='menucl' id='" + menuid + "'</ul>");
mymenu = $("#" + menuid);
mymenu.append("<li>first</li><li>counting " + count + "</li><li>last</li>")
mymenu.menu({
select: function(ev, ui) {
console.log("selected ui=", ui);
$("#message_id").html("<b>selected</b> <i>" + ui.item.text() + "</i> menu#" + count);
}
});
mymenu.mousemove(function(ev) {
console.log("mousemove ev=", ev);
clearTimeout(menuTO);
menuTO = setTimeout(fadeOutMenu,
9000);
//mymenu.finish();
})
menuTO = setTimeout(fadeOutMenu,
9000);
})
})
ul.menucl {
background-color: lightpink;
color: navy;
font-size: 80%;
display: inline-block;
}
p.explaincl {
font-size: 75%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<p>
See <a href='http://stackoverflow.com/q/34818540/841108'>this SO question</a>
</p>
<h2> my menu </h2>
<p class='explaincl'>
First, try clicking the button, and do nothing more: the menu disappears in 10 sec. Then, try again, click the button, move the mouse inside the menu, it is still disappearing but I want it to stay!</p>
<button id='mybutton_id'>click me</button>
<div id='mymenudiv_id'>
Here
</div>
<p id='message_id'>
</p>
I have stored Timeout id in a variable menuTO. Then on every mousemove I reset Timeout so that the menu won't fade out if mouse is moving inside the menu.
Also keep in mind if your cursor is inside menu but is not moving, then it will obviously fade out in next 9 to 10 seconds.

The accepted answer will unnecessarily create and clear huge lot of timeouts when the mouse moves around.
You can use the built in menu event focus and blur to better handle this as shown below:
mymenu.menu({
focus: function(e, ui) {
clearTimeout($(this).data('timeout'));
}
});
mymenu.on('menublur', function(e, ui) {
var timeout = setTimeout(function() {
console.log("fading mymenu");
}, 5000);
$(this).data('timeout', timeout);
});
mymenu.trigger('menublur'); // start the timeout for the first time
menublur is an internal (documented) jquery ui event which is triggered when a menu item lose focus.
Note that we should bind the event you want to trigger manually using on() method, outside the options object.
Updated Fiddle

Related

How to show divs when the mouse moves anywhere on screen, not just the element itself?

I managed to hide and show my classes when the user moves his mouse over the specific element. But what I would actually like is that these show when the user moves his mouse anywhere on the screen, not just the selected div's.
This is my current code:
$(window).on('mousemove', function () {
$('.barhide').addClass('show');
try {
clearTimeout(timer);
} catch (e) {}
timer = setTimeout(function () {
$('.barhide').removeClass('show');
}, 1000);
});
And my css:
.barhide {
background: #333;
color: #fff;
display: block;
opacity: 0;
transition: all 1.5s ease;
}
.barhide.show {
opacity: 1;
display: none;
}
So what I would like is that after 3 seconds, the classes with .barhide get hidden and if the user moves his mouse anywhere in screen, they show up again, instead of just when they move over the element.
Also I was wondering if it's not a lot easier to do these things with React?
I have restructured the code a bit and added some comments explaining what's happening and when. Also, lose the try since attempting to clear a timer will never throw an exception.
Keep in mind that mouseover type events are an issue on mobile devices. These two articles may help in that regard:
JQuery's Virtual Mouse Events
Simulated Mouse Events using JQuery
$(function(){
// When page loads, wait 3 seconds and hide all elements with .barhide class:
setTimeout(toggle, 3000);
});
var timer = null;
// General function for adding/removing the "hide" class.
// This is used when the page first loads and each time
// the mouse moves on the page. We're not calling toggle()
// here because a flicker effect can happen which would leave
// the elements showing instead of being hidden.
function toggle(){
$('.barhide').toggleClass('hide');
}
$(window).on('mousemove', function(){
// When anywhere on page is moused over bring back .barhide
// elements for 3 seconds. Removing "hide" simply restores
// the original CSS & layout
$('.barhide').removeClass('hide');
// Kill any previous timers
clearTimeout(timer);
// Wait 3 seconds and hide again
timer = setTimeout(toggle, 3000)
});
.barhide { background-color:blue; }
.hide { display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="barhide">ONE</div>
<div class="show">TWO</div>
You just count the nr of timers running and when the last finishes you hide the bar.
var count = 0;
$(window).mousemove(function( event ) {
$('.barhide').show();
count += 1;
setTimeout(function() {
if (count == 1) {
$('.barhide').hide();
}
count -= 1;
}, 3000);
});

Using a jquery slider for text instead of images?

This may be a little too specific, but I have a jquery slider that I am using <p> classes instead of images to cycle through customer quotes. Basically the problem I am running into right now is when it is static and non moving (JS code is commeneted out) they are aligned how I want them to be. As soon as the JS is un commented, they stretch out of view and you just see a white box?
Any ideas?
How I want each panel to look like:
jsfiddle
So I sort of made this my Friday project. I've changed a whole lot of your code, and added a vertical-align to the quotes and authors.
Here's the fiddle http://jsfiddle.net/qLca2fz4/49/
I added a whole lot of variables to the top of the script so you could less typing throughout.
$(document).ready(function () {
//rotation speed and timer
var speed = 5000;
var run = setInterval(rotate, speed);
var slides = $('.slide');
var container = $('#slides ul');
var elm = container.find(':first-child').prop("tagName");
var item_width = container.width();
var previous = 'prev'; //id of previous button
var next = 'next'; //id of next button
Since you used a % based width I'm setting the pixel widths of the elements in case the screen is reszed
slides.width(item_width); //set the slides to the correct pixel width
container.parent().width(item_width);
container.width(slides.length * item_width); //set the slides container to the correct total width
As you had, I'm rearranging the slides in the event the back button is pressed
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
I combined the prev and next click events into a single function. It checks for the ID of the element targeted in the click event, then runs the proper previous or next functions. If you reset the setInterval after the click event your browser has trouble stopping it on hover.
//if user clicked on prev button
$('#buttons a').click(function (e) {
//slide the item
if (container.is(':animated')) {
return false;
}
if (e.target.id == previous) {
container.stop().animate({
'left': 0
}, 1500, function () {
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
});
}
if (e.target.id == next) {
container.stop().animate({
'left': item_width * -2
}, 1500, function () {
container.find(elm + ':last').after(container.find(elm + ':first'));
resetSlides();
});
}
//cancel the link behavior
return false;
});
I've found mouseenter and mouseleave to be a little more reliable than hover.
//if mouse hover, pause the auto rotation, otherwise rotate it
container.parent().mouseenter(function () {
clearInterval(run);
}).mouseleave(function () {
run = setInterval(rotate, speed);
});
I broke this in to its own function because it gets called in a number of different places.
function resetSlides() {
//and adjust the container so current is in the frame
container.css({
'left': -1 * item_width
});
}
});
//a simple function to click next link
//a timer will call this function, and the rotation will begin :)
And here's your rotation timer.
function rotate() {
$('#next').click();
}
It took me a little bit, but I think I figured out a few things.
http://jsfiddle.net/qLca2fz4/28/
First off, your console was throwing a few errors: first, that rotate wasn't defined and that an arrow gif didn't exist. Arrow gif was probably something you have stored locally, but I changed the 'rotate' error by changing the strings in the code here to your actual variables.
So, from:
run = setInterval('rotate()', speed);
We get:
run = setInterval(rotate, speed);
(No () based on the examples here: http://www.w3schools.com/jsref/met_win_setinterval.asp)
But I think a more important question is why your text wasn't showing up at all. It's because of the logic found here:
$('#slides ul').css({'left' : left_value});
You even say that this is setting the default placement for the code. But it isn't..."left_vaule" is the amount that you've calculated to push left during a slide. So if you inspect the element, you can see how the whole UL is basically shifted one slide's worth too far left, unable to be seen. So we get rid of 'left_value', and replace it with 0.
$('#slides ul').css({'left' : 0});
Now, there's nothing really handling how the pictures slide in, so that part's still rough, but this should be enough to start on.
Let me know if I misunderstood anything, or if you have any questions.
So, a few things:
1) I believe you are trying to get all of the lis to be side-by-side, not arranged up and down. There are a few ways to do this. I'd just make the ul have a width of 300%, and then make the lis each take up a third of that:
#slides ul {
....
width: 300%;
}
#slides li {
width: calc(100% / 3);
height:250px;
float:left;
}
2) You got this right, but JSFiddle automatically wraps all your JS inside a $(document).ready() handler, and your function, rotate needs to be outside, in the normal DOM. Just change that JSFiddle setting from 'onload' to 'no wrap - in head'
3) Grabbing the CSS value of an element doesn't always work, especially when you're dealing with animating elements. You already know the width of the li elements with your item_width variable. I'd just use that and change your code:
var left_indent = parseInt($('#slides ul').css('left')) - item_width;
$('#slides ul').animate({'left' : left_indent}, 1500, function () {
to:
$('#slides ul').stop().animate({'left' : -item_width * 2}, 1500, function () {
4) Throw in the .stop() as seen in the above line. This prevents your animations from overlapping. An alternative, and perhaps cleaner way to do this, would be to simply return false at the beginning of your 'next' and 'prev' functions if #slides ul is being animated, like so:
if ($('#slides ul').is(':animated')) return false;
And I think that's everything. Here's the JSFiddle. Cheers!
EDIT:
Oh, and you may also want to clearInterval at the beginning of the next and prev functions and then reset it in the animation callback functions:
$('#prev').click(function() {
if ($('#slides ul').is(':animated')) return false;
clearInterval(run);
$('#slides ul').stop().animate({'left' : 0}, 1500,function(){
....
run = setInterval('rotate()', speed);
});
});

change id of button depending on current viewed div

ive a problem which is driving me crazy. im trying to explain...
i have a very long scrolling page with about 10 divs, one below the other (no space between).
at the bottom of the viewing port is a button with an id and a position: fixed. when i scroll up or down the button is fixed while the divs move up or down.
i want to have different id's on the button depending on which div layer is in the viewing port. that means if one divlayer fills over 50% of the available space the href of the button should change...
i tried the inview.js, but the problem is, that 2 divs at the same time have the inview class...
my current code:
$('#div4, #div5, #div6').bind('inview', function (event, visible) {
if (visible == true) {
$(this).addClass("inview");
} else {
$(this).removeClass("inview");
}
});
var $div4 = $('#div4');
if($div4.hasClass("inview")){
$('#button1').attr('id', 'button2');
}
you see, every div which is in the viewport the button gets a new id.
has anyone of you a solution?
thanks ted
You can try to remove the inview class before adding it.. Something like this:
var $divs = $('#div4,#div5,#div6';
$divs.bind('inview', function (event, visible) {
$divs.not(this).removeClass("inview");
if (visible == true) {
$(this).addClass("inview");
}
});
Another suggestion is to use the Waypoints plugin and fire when the div crosses the 50% mark.
The only difficult part is that depending on the direction you'll need to select the current div or the one above.
Plugin: http://imakewebthings.com/jquery-waypoints/
Demo: http://jsfiddle.net/lucuma/nFfSn/1/
Code:
$('.container div').waypoint(function (direction) {
if (direction=='up')
alert('hit ' + $.waypoints('above')[$.waypoints('above').length-2].id);
else
alert('hit ' + $(this).attr('id'));
}, {
offset: $.waypoints('viewportHeight') / 2
});

Show / hide elements on mouse move

I'm building a site where I want the certain sections to be hidden until the mouse is moved. They then remain visible whilst the mouse is moving, however, if it remains still for a couple of seconds they hide again.
I'm using jQuery on the site, in my ready state I have:
var hide = setTimeout(function() {
hideNav();
}, 2000);
$('body').mousemove(function() {
clearTimeout(hide);
var hide = setTimeout(function() {
hideNav();
}, 2000);
showNav();
});
And the functions that show/hide content
function hideNav() {
$('#primary').fadeOut(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeOut(1000);
}
}
function showNav() {
$('#primary').fadeIn(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeIn(1000);
}
}
This sort of works, except the timeout for hiding the elements ends up fighting with the function to show it when the mouse moves resulting in a lot of flickering.
EDIT: The mouse movement needs to be for anywhere on the page, not just when hovering over the element that is to be shown/hidden.
Any help would be appreciated.
Thanks
Try using $.stop http://api.jquery.com/stop/
If its in the 1 second of fading out when you move your mouse, it should stop the animation of fading out and fade back in.
function hideNav() {
$('#primary').stop().fadeOut(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeOut(1000);
}
}
function showNav() {
$('#primary').stop().fadeIn(1000);
var lightbox = $('#lightbox');
if (lightbox.length) {
lightbox.fadeIn(1000);
}
}
Also, I would remove var from the var hide = ... in your mousemove function. If hide is a global variable, just reuse it inside mousemove (doesn't need to be redeclared).

jQuery and CSS Menu Help!

I'm attempting to make a menu bar that sticks to the bottom of the screen. Due to it's position on the screen I can't use anchor tags for hyperlinking because in Google Chrome it causes that small link bar to appear in the bottom corner (which overlays ontop of the menu).
As such, each menu icon is a DIV with a unique ID (eg. "profile") and the class "menu-item" is applied to it. Each of these icons will link to a specific page when clicked on (eg. why I want to use the onClick javascript event). However, when each of these icons is hovered over it pops a contextual tooltip (or submenu) above it. Inside this tooltip a further options or links. Consequently, I have come up with the following html construct:
example image located here: http://i.stack.imgur.com/hZU2g.png
Each menu icon will have its own unique onClick link, as well as its own unique submenu/tooltip (which may have more links to different pages).
I am using the following jQuery to pop each submenu:
$(".menu-item").hover(function() {
$('#' + this.id + '-tip').fadeIn("fast").show(); //add 'show()'' for IE
},
function() { //hide tooltip when the mouse moves off of the element
$('#' + this.id + '-tip').hide();
}
);
The issue I'm having is keeping the tooltip visible when the cursor is moved off the icon and onto the submenu/tooltip (currently it disappears the second the icon is no longer hovered on). I want to jQuery fadein and fadeout effects to be applied to the appearance of the tooltip/submenu.
Comments, suggestions, code and jsfiddle examples would be greatly appreciated. Happy to clarify further if I was unclear on any aspects.
Thanks in advance.
You need to wrap the menu-item and tip links in a parent div like so:
<div class="item-wrapper" rel="profile">
<div id="profile" class="menu-item"></div>
<div id="profile-tip" class="tip">
Link1
Link2
</div>
</div>
Then apply the hover function to .item-wrapper and reference the rel attribute (or any other attribute of your choosing):
$(".item-wrapper").hover(function() {
$('#' + $(this).attr("rel") + '-tip').fadeIn("fast").show(); //add 'show()'' for IE
},
function() { //hide tooltip when the mouse moves off of the element
$('#' + $(this).attr("rel") + '-tip').hide();
});
This way when you hover over the links you will still be hovering over the .item-wrapper div.
UPDATE:
To answer your follow-up question, you will need to use setTimeout():
var item_wrapper = {
onHover: function($obj, delay) {
setTimeout(function() {
$('#' + $obj.attr("rel") + '-tip').fadeIn("fast").show(); //add 'show()'' for IE
}, delay);
},
offHover: function($obj, delay) {
setTimeout(function() {
$('#' + $obj.attr("rel") + '-tip').hide();
}, delay);
},
initHover: function($obj, delay) {
$obj.hover(function() {
item_wrapper.onHover($(this), delay);
}, function() {
item_wrapper.offHover($(this), delay);
});
}
};
item_wrapper.initHover($(".item-wrapper"), 1000);
The second argument to setTimeout() is the delay in milliseconds.

Categories

Resources