I have some elements that, upon hover, toggle the display (none/block) of a child ul. Unfortunately, I can't transition a fade via CSS with display. Using opacity won't work either since the hover area expands onto the opacity: 0 ul, and a combo of both (transition opacity, but still toggle display) doesn't seem to work.
Is there a way to intercept the display change via Javascript, and have it fade between block and none? Are there alternate suggestions (I tried a height: 0/auto toggle too, didn't work right)? I'd prefer an intercept method than a pure JS method, in case JS is disabled or something.
If I understand you correctly. Assuming something like: <div class="nav-container"><ul></ul></div>.
You can listen for hover on the parent, since it contains the child:
var parent = document.getElementsByClassName('nav-container')[0];
var connect = function (element, event, callback) {/* I think you */};
var disconnect = function (handle) { /* can find */};
var addClass = function (element, className) { /* these elsewhere. */};
var removeClass = function (element, className) { /* ... */};
var hoverHandle = connect(parent, 'hover', function (event) {
addClass(parent, 'hovered');
if (blurHandle) {
disconnect(blurHandle);
}
});
var blurHandle = = connect(parent, 'blur', function (event) {
removeClass(parent, 'hovered');
if (hoverHandle) {
disconnect(hoverHandle);
}
});
Then in the CSS:
.nav-container > ul {
display: none;
/* do fade out */
}
.nav-container.hovered > ul {
display: block;
/* do fade in */
}
If you're using jQuery 1.7, then this'll become:
var navContainers = $('.nav-container');
navContainers.on('hover', function () {
$(this).toggleClass('hovered');
});
navContainers.on('blur', function () {
$(this).toggleClass('hovered');
});
Related
I have many bootstrap popovers on a page, but the first one, triggered by an with an id, I need to make scrollable (and have included js to make it stay open to scroll), which is trivial enough in css, but I haven't been able to make only that specific one scroll, the others do also...:
.popover-content {
max-height: 100px;
overflow-y: auto;
}
$(document).ready(function() {
$("#scrollpop").popover({ trigger: "manual" , html: true})
.on("mouseenter", function () {
var _this = this;
$(this).popover("show");
$(".popover").on("mouseleave", function () {
setTimeout(function () {
if (!$(".popover:hover").length) {
$(_this).popover("hide");
}
}, 100);
});
}).on("mouseleave", function () {
var _this = this;
setTimeout(function () {
if (!$(".popover:hover").length) {
$(_this).popover("hide");
}
}, 100);
});
});
Text Here
Is there a way to do this, without being to invasive and work for IE8/IE9 browsers?
Thank you!
I've just had a look locally, it looks like Bootstrap adds popover elements after the element in which you target your popover to be triggered on, e.g.
$('#test').popover();
<span id="test">Hello world!</span>
<!-- popover gets generated here -->
So, you can use the adjacent sibling selector in CSS to target the fact that the popover container element is a directly following sibling of the original element. You then use a .popover-content selector after that to target the child element of the popover container (your example now):
/* target .popover-content elements that are children of .popover
elements that occur directly after the #scrollpop element */
#scrollpop + .popover .popover-content {
max-height: 100px;
overflow-y: auto;
}
Edit: updated fiddle.
I have an element, which fills the screen. Under that I have another element which does NOT fill the screen but is hidden. So you can't manually scroll to that.
The first element which is filling the screen has the following CSS properties:
header {
position: relative;
height: 100vh;
background-color: green;
}
And the second element has these CSS properties:
#content {
display: none;
position: relative;
height: 1500px;
width: 100%;
background-color: yellow;
}
I use this code to trace the scrolling:
$('header').bind("DOMMouseScroll mousewheel", function(e) {
...
});
Inside this method I check which panel is activated (by a self created boolean) and which direction I'm scrolling to, by doing this:
$('header').bind("DOMMouseScroll mousewheel", function(e) {
var wheelDelta = e.originalEvent.wheelDelta;
if (active === header && wheelDelta <= 0) {
...
}
});
Inside that if statement I give call a method that displays the #content element below it and smoothly scrolls to it, and when its done scrolling it hides the element where we have scrolled from (header). I'm using this piece of code for that:
$('body').bind("DOMMouseScroll mousewheel", function (e) {
event.preventDefault();
var wheelDelta = e.originalEvent.wheelDelta;
$('header').unbind("DOMMouseScroll mousewheel");
if (active === header && wheelDelta <= 0) {
showScrollHide(500, content, 1000, header, 250, function () {
_window.scrollTop(0);
_scrollBackBtn.fadeIn();
active = content;
});
}
});
This works perfectly, whenever I scroll down on the header element while its active. It smoothly scrolls down to the #content element under it.
There I have a button which scrolls back up the page, I have this code for it:
_scrollBackBtn.on('click', function() {
if (active === content) {
active = header;
scrollBackHide(header, content, 500, 250, function() {
window.location = '#';
});
}
});
Which also works perfectly, it scrolls back to the top of the page.
But whenever I try to scroll down again, it doesn't do anything. How does this come?
I had to add $('header').unbind("DOMMouseScroll mousewheel"); to the code, otherwise it looked very ugly in the end result.
Whenever I added $('header').stop(); in the same section, it didn't make any difference.
So my question is. How can this .bind method be used again for the same thing?
Here's a demo if you don't understand what I mean. Whenever you scroll down on the header element, and scroll back up via the button. Its not doing the same again.
You are unbinding your mousewheel handlers when they run once and then never re-binding them, so there are no event handlers in place to react to mousewheel events after you click the button. Re-binding that event handler when you click the button does the trick.
Here is a fiddle that does that and should point you in the right direction.
I pulled your mousewheel handler out into a function so we can reuse it whenever we need to bind those events:
var handleMouseWheel = function(e){
e.preventDefault();
var wheelDelta = e.originalEvent.wheelDelta;
if (active === header && wheelDelta <= 0) {
$('body').unbind("DOMMouseScroll mousewheel");
showScrollHide(500, content, 1000, header, 250, function () {
_window.scrollTop(0);
_scrollBackBtn.fadeIn();
active = content;
});
}
};
and use that to reattach an event handler when the button is clicked:
_scrollBackBtn.on('click', function () {
if (active === content) {
scrollBackHide(header, content, 500, 250, function () {
window.location = '#';
active = header;
});
$('body').bind("DOMMouseScroll mousewheel", handleMouseWheel);
}
});
I have a menu that when hovered, shows the subnav of the current hovered item by adding .stick to the submenu and removing it on mouseleave. If not hovering on another menu item I want the last hovered menu item to stay open for another 2 seconds before hiding.
Here's what I have. I know that the mouseleave() called on the container won't work since it's within the handlerOut of the ul#main-nav > li hover function but I left it to show you where I last left off.
$('ul#main-nav > li').hover(function() {
var $this = $(this);
clearTimeout(window.menustick);
$this.find('ul.submenu').addClass('stick');
}, function() {
var $this = $(this);
if($this.siblings().hover()) {
$this.find('ul.submenu').removeClass('stick');
} else if ($('#main-nav').mouseleave()) {
window.menustick = setTimeout(function(){
$this.find('ul.submenu').removeClass('stick');
}, 2000);
}
});
Here's the jsFiddle.
Thanks in advance!
JS:
$("ul#main-nav > li").hover(
function(){
$(this).children('ul').hide().fadeIn(500);
},
function () {
$('ul.submenu', this).fadeOut(2000);
});
Fiddle: http://jsfiddle.net/3F7bJ/3/
You had a couple of issues with your scripts and CSS.
Firstly, your CSS had the following rule:
nav ul#main-nav li:hover > ul.submenu {
display: block;
}
This needs to be modified to:
nav ul#main-nav li > ul.submenu.stick {
display: block;
}
This meant that your CSS was controlling the visibility rather than the class 'stick'.
As you mentioned the use of .hover() and .mouseleave() in the script code is incorrect and not required. As at that point you are already in the mouseleave (handlerOut) of the hover.
The below code appears to perform the desired effect you were looking for:
var menuStickTimeoutId;
$('ul#main-nav > li').hover(function () {
var $this = $(this);
clearTimeout(menuStickTimeoutId);
$('#main-nav ul.submenu').removeClass('stick');
$this.find('ul.submenu').addClass('stick');
}, function () {
var $this = $(this);
clearTimeout(menuStickTimeoutId);
menuStickTimeoutId = setTimeout(function () {
$this.find('ul.submenu').removeClass('stick');
}, 2000);
});
Working demo:
http://jsfiddle.net/3F7bJ/2/
I have some elements which have hover effects as well as should be selected when clicked. Currently when I add the stop() to the effect it causes the animation to stop in place when clicked. I tried using fadeToggle() for the same effect but could not wrap my head around how to get it to function properly. The id I am targeting are passed to the href of the clicked element.
Can someone give pointers on the best way to write this script?
$(function() {
$("#map-hovers > ul > li").hide();
$('area').click(function(e) {
e.preventDefault();
var $hoodClick = $($(this).attr('href'));
if ($hoodClick.hasClass('selected')) {
$($hoodClick).fadeOut().removeClass('selected');
} else {
$($hoodClick).fadeIn().addClass('selected');
}
}).hover(function() {
var $hoodHoverOver = $($(this).attr('href'));
$hoodHoverOver.fadeIn();
},
function() {
var $hoodHoverOut = $($(this).attr('href'));
if ($hoodHoverOut.hasClass('selected')) {
} else {
$hoodHoverOut.fadeOut();
}
})
});
Use .stop(true, true). It skips to the end of the animation & clears the animation queue. Read more about it in the API: http://api.jquery.com/stop/
I've created DIV.cb-toggle, when the user hovers over this div, it animates to Orange, when they hover off of this div, it animates back to gray, when the user clicks this div, it animates to blue, telling the user that it's been selected. So when it's NOT selected, it has mouseenter mouseleave animations, but when it's selected i want to unbind these events, I DO NOT want the hover event to work when it's been selected, only when it's not selected. What's the best way to do what i'm trying to accomplish? I came up with the code below but i'm pretty sure this is a horrible way to do it and i don't know what to do. thank you so much for any help.
my code:
$('.cb-toggle').toggle(function() {
$(this).animate({"background":"blue", "color":"#fff;"});
$(".cb-toggle").unbind("click.myfadee");
}, function() {
$(this).animate({"background":"gray", "color":"#fff;"});
$('.cb-toggle').trigger('mouseenter');
});
});
and I'm calling this bind:
$(".cb-toggle").bind("click.myfadee", function(){
$(".cb-toggle").mouseenter(function() {
$(this).animate({"background":"orange", "color":"#fff;"});
}).mouseleave(function() {
$(this).animate({"background":"gray", "color":"#fff;"});
});
});
I need to keep the background color animation, it needs to fade.
I would use CSS for the styling to simplify your whole setup without un/re-binding, like this:
.cb-toggle { background: blue; color: #fff; }
.cb-toggle.active { background: gray; }
.cb-toggle.active:hover { background: orange; }
Then you can do just this:
$('.cb-toggle').click(function() {
$(this).toggleClass("active");
});
This approach also lets you offload all styling, colors, etc to the CSS, meaning no JavaScript changes are needed when you decide to tweak the colors or any other styling :)
Or, if you need to support IE6, add a .live() handler for the hover that triggers on only the ones with the .active class, like this:
$(".cb-toggle.active").live('mouseenter', function() {
$(this).addClass('hover');
}).live('mouseleave', function() {
$(this).removeClass('hover');
});
With matching CSS:
.cb-toggle.active.hover { background: orange; }
You should probably just use a selected class. Also I'd recommend against using any of the .css() calls you have here. Just use classes.
$(".cb-toggle").bind("click.myfadee", function(){
$(this).toggleClass('selected');
});
$('.cb-toggle').toggle(function() {
var $this = $(this);
if ( $this.is('.selected') ) {
$this.css({"background":"blue", "color":"#fff;"});
}
}, function() {
var $this = $(this);
if ( $this.is('.selected') ) {
$this.css({"background":"gray", "color":"#fff;"});
}
});