Reputation: 12010
On my site I have hover cards on users' profile pictures. I'm having two issues.
The first issue I am having is that it doesn't work that nicely in terms of showing and hiding when you move your mouse on or off of the profile picture. When you move your mouse over a picture quickly (like if you are just moving your mouse across the page) after about a second it still pops up. I don't see why though it's doing this though. Only after 1000 milliseconds of hovering should the card pop up.
The second issue I am having is that if you are hovering over one picture and you move to another picture (like one that is right above it) before the other one closes it just won't work until you move your mouse off the picture and then move it back over it.
I'm wondering if there is just a better way to do the mouseenter and mouseleave events than how I am doing it right now.
Here's my JavaScript for the hover card:
var timeout, timeout2, hovercard_request;
$('.profile-hovercard').live('mouseenter',function() {
if(!$('#hovercard').hasClass('open')) {
var id = $(this).attr('data-id'),
pos = $(this).offset(),
width = $(this).outerWidth(),
miniprofile_url = $(this).parent().attr('href') + '/mini_profile';
timeout = setTimeout(function() {
//$('#hovercard').remove();
if ($('#hovercard').length <= 0) {
var hc = '<div id="hovercard" class="open"> \
<div class="hovercard-loading"><img src="/assets/img/ProgressIndicator.gif" /></div> \
</div>';
$('body').append(hc);
$('#hovercard').css({
'position': 'absolute',
'top': pos.top + "px",
'left': (pos.left + width + 11) + "px"
});
}
else {
$('#hovercard').css({
'position': 'absolute',
'top': pos.top + "px",
'left': (pos.left + width + 11) + "px"
}).html('<div class="hovercard-loading"><img src="/assets/img/ProgressIndicator.gif" /></div>').show().addClass('open');
}
$.get(miniprofile_url, {}, function(data) {
$('#hovercard').html('<div class="hovercard-inner"> \
<div class="hovercard-pic"> \
<a href="'+data.url+'"><img src="' + data.img_path + '" alt="' + data.name + '" /></a> \
</div> \
<div class="hovercard-details"> \
<h3><a href="'+data.url+'">' + data.name + ( data.you == 1 ? ' <span style="font-weight:normal">(you)</span>' : '' ) + '</a> ' + ( data.is_online ? '<span class="online-user-icon m" title="'+data.name+' is online."></span>' : '') + '</h3> \
<div class="hovercard-stats"> \
<strong class="points">' + data.points + ' point' + (data.points == 1 ? '' : 's') + '</strong><br /> \
<strong>' + data.questions + '</strong> question' + (data.questions == 1 ? '' : 's') + ' / <strong>' + data.answers + '</strong> answer' + (data.answers == 1 ? '' : 's') + '<!-- / <strong>' + data.comments + '</strong> comment' + (data.comments == 1 ? '' : 's') + '--><br /> \
<span class="location">' + data.location + '</span> \
</div> \
</div> \
<div class="clear"></div> \
</div>');
if(data.bio !== '') {
$('#hovercard').append('<div class="hovercard-bio">' + data.bio + '</div>');
}
else {
$('#hovercard').append('<div class="hovercard-bio"><em>This user does not have a bio.</em></div>');
}
},'json').fail(function() {
$('#hovercard').html('<div class="hovercard-loading">The request has failed. Please try again later.</div>');
}).error(function() {
$('#hovercard').html('<div class="hovercard-loading">An error has occurred. Please try again later.</div>');
});
}, 1000);
} // end if
});
$('.profile-hovercard').live('mouseleave',function() {
clearTimeout(timeout);
//hovercard_request.abort();
timeout2 = setTimeout(function() {
$('#hovercard').hide().removeClass('open');
}, 400);
$('#hovercard').hover(function() {
clearTimeout(timeout2);
},function() {
timeout2 = setTimeout(function() {
$('#hovercard').hide().removeClass('open');
}, 300);
});
});
When you hover over someone's picture, it pops up a little box next to it showing some of their info. In the above code I have all the timeouts because that is the only way I could get the card to stay open so someone could move their mouse to the card without the card closing.
Upvotes: 0
Views: 1955
Reputation: 23575
Here's one way you could do it:
var timeout;
$('.profile').hover(function() {
pos = $(this).offset();
timeout = setTimeout(function() {
$('.hovercard').fadeIn().css({
'top': pos.top - 20 + 'px',
'left': pos.left - 20 + 'px'
});
}, 1000);
}, function() {
clearTimeout(timeout);
});
$('.hovercard').mouseleave(function() {
$('.hovercard').fadeOut();
});
Basically, you give the hovercard extra padding so that it covers the profile picture as well. This means you can use the profile picture for the mouseenter
event and the hovercard for the mouseleave
event.
Example: http://jsfiddle.net/grc4/C8VTS/1/
Upvotes: 1
Reputation: 1598
You could try adding clearTimeout(x);
before your setTimeout
. This should make sure the timer isn't started twice.
Still this code could use some refactoring; the mouseenter handler is so long it makes it harder to understand what it does and to debug.
var timeout, timeout2, hovercard_request;
$('.profile-hovercard').live('mouseenter', function() {
if (!$('#hovercard').hasClass('open')) {
var id = $(this).attr('data-id'),
pos = $(this).offset(),
width = $(this).outerWidth(),
miniprofile_url = $(this).parent().attr('href') + '/mini_profile';
clearTimeout(timeout);
timeout = setTimeout(function() {
//$('#hovercard').remove();
if ($('#hovercard').length <= 0) {
var hc = '<div id="hovercard" class="open"> \
<div class="hovercard-loading"><img src="/assets/img/ProgressIndicator.gif" /></div> \
</div>';
$('body').append(hc);
$('#hovercard').css({
'position': 'absolute',
'top': pos.top + "px",
'left': (pos.left + width + 11) + "px"
});
}
else {
$('#hovercard').css({
'position': 'absolute',
'top': pos.top + "px",
'left': (pos.left + width + 11) + "px"
}).html('<div class="hovercard-loading"><img src="/assets/img/ProgressIndicator.gif" /></div>').show().addClass('open');
}
$.get(miniprofile_url, {}, function(data) {
$('#hovercard').html('<div class="hovercard-inner"> \
<div class="hovercard-pic"> \
<a href="' + data.url + '"><img src="' + data.img_path + '" alt="' + data.name + '" /></a> \
</div> \
<div class="hovercard-details"> \
<h3><a href="' + data.url + '">' + data.name + (data.you == 1 ? ' <span style="font-weight:normal">(you)</span>' : '') + '</a> ' + (data.is_online ? '<span class="online-user-icon m" title="' + data.name + ' is online."></span>' : '') + '</h3> \
<div class="hovercard-stats"> \
<strong class="points">' + data.points + ' point' + (data.points == 1 ? '' : 's') + '</strong><br /> \
<strong>' + data.questions + '</strong> question' + (data.questions == 1 ? '' : 's') + ' / <strong>' + data.answers + '</strong> answer' + (data.answers == 1 ? '' : 's') + '<!-- / <strong>' + data.comments + '</strong> comment' + (data.comments == 1 ? '' : 's') + '--><br /> \
<span class="location">' + data.location + '</span> \
</div> \
</div> \
<div class="clear"></div> \
</div>');
if (data.bio !== '') {
$('#hovercard').append('<div class="hovercard-bio">' + data.bio + '</div>');
}
else {
$('#hovercard').append('<div class="hovercard-bio"><em>This user does not have a bio.</em></div>');
}
}, 'json').fail(function() {
$('#hovercard').html('<div class="hovercard-loading">The request has failed. Please try again later.</div>');
}).error(function() {
$('#hovercard').html('<div class="hovercard-loading">An error has occurred. Please try again later.</div>');
});
}, 1000);
} // end if
});
$('.profile-hovercard').live('mouseleave', function() {
clearTimeout(timeout2);
//hovercard_request.abort();
timeout2 = setTimeout(function() {
$('#hovercard').hide().removeClass('open');
}, 400);
$('#hovercard').hover(function() {
clearTimeout(timeout2);
}, function() {
clearTimeout(timeout2);
timeout2 = setTimeout(function() {
$('#hovercard').hide().removeClass('open');
}, 300);
});
});
Upvotes: 2