Kendo UI Tooltip Will Sometimes Remain Visible When it should Disappear - javascript

I have been playing around with this for quite some time, and I do not know what is wrong. When I have a few links in a row, and keep fluttering my mouse cursor over them quickly every so often a tooltip will remain visible when it should go away (it is visible even after the cursor is no longer on the link).
I believe my code is logically valid, can someone else see if they know why a tooltip here and there would remain visible?
For a link of this type:
Link
Here is the code:
function tooltip(e) {
var ticketType = j$(e).data("ticket-type");
var ticketID = j$(e).data("ticket-id");
j$.post("/Some/Url/", { "ticketID":ticketID, "ticketType":ticketType },
function(r) {
var title = r["tt"];
var tooltip = j$(e).kendoTooltip( { content: title, position: "top" } ).data("kendoTooltip");
}).always(function() {
if (j$(e).is(":hover")) { j$(e).data("kendoTooltip").show(); }
else { j$(e).data("kendoTooltip").hide(); }
});
j$(e).hover(function() {},
// Handler for when the pointer is leaving an element
function(e) {
if (j$(e.target).data("kendoTooltip") != undefined) {
j$(e.target).data("kendoTooltip").hide();
.log(e.target.innerHTML + ": was hidden.");
}
}
);
}

I think the problem is that sometimes you mouseout before ajax post returns, therefore the tooltip is shown after you leave a link. As well as hiding on mouseout, how about setting a data attribute on the target link so that the AJAX return can check the attribute before showing the tooltip:
function tooltip(e) {
j$(e).data("hover", "true"); //turn on hover data-attribute
var ticketType = j$(e).data("ticket-type");
var ticketID = j$(e).data("ticket-id");
j$.post("/Some/Url/", { "ticketID":ticketID, "ticketType":ticketType },
function(r) {
var title = r["tt"];
var tooltip = j$(e).kendoTooltip( { content: title, position: "top" } ).data("kendoTooltip");
}).always(function() {
if (j$(e).data("hover") == "true") { j$(e).data("kendoTooltip").show(); }
else { j$(e).data("kendoTooltip").hide(); }
});
j$(e).hover(function() {},
// Handler for when the pointer is leaving an element
function(e) {
j$(e).data("hover", "false"); //turn offhover data-attribute
if (j$(e.target).data("kendoTooltip") != undefined) {
j$(e.target).data("kendoTooltip").hide();
.log(e.target.innerHTML + ": was hidden.");
}
}
);
}
DEMO
NOTE: demo uses a setTimeout to fake an ajax call

Related

How to keep Skrollr-Menu at an even speed?

I'm using Skrollr-menu to animate down a page on a button press using the following
HTML
<div class="trigger-scroll left">></div>
... the page i want to reveal, using scrolling ...
<section id="End" class="scroll-here">
<div class="hsContainer bottom"></div>
</section>
JavaScript
var s = skrollr.init();
skrollr.menu.init(s, {
animate: true,
//How long the animation should take in ms.
duration: function(currentTop, targetTop) {
//By default, the duration is hardcoded at 500ms.
return 18000;
//But you could calculate a value based on the current scroll position (`currentTop`) and the target scroll position (`targetTop`).
//return Math.abs(currentTop - targetTop) * 10;
},
//This event is triggered right before we jump/animate to a new hash.
change: function(newHash, newTopPosition) {
//Do stuff
},
//Add hash link (e.g. `#foo`) to URL or not.
updateUrl: false //defaults to `true`.
});
What happens when I click the button is that it works, that is not the problem.
The problem is that it seems to change speed as skrollr-menu animates the page. It starts off quite quickly, which means that the first few elements on the page (about the first 2000px) flash past without being readable. Then the speed evens out and is fine right until the last 3000px (approximately) where skrollr-menu is very slow. What I want is for the click of the button to resemble holding the down arrow on the keyboard or the scroll sidebar, which by default it seems skrollr-menu does not do.
I've tried using math equations to change the speed but the issue persists no matter what i try, and there doesn't seem to be any "simple" way to change the acceleration speed, and I suspect the problem is somewhere within the Skrollr.menu.js file, but I can't see where.
Is there any way which I can make the scrolling an even speed, rather than fast at the start and slow at the end?
Note: I'm not very experienced in JavaScript or jQuery, so it's probably something simple I've overlooked.
skrollr menu on github
https://github.com/Prinzhorn/skrollr-menu
Skrollr.menu.js
/*!
* Plugin for skrollr.
* This plugin makes hashlinks scroll nicely to their target position.
*
* Alexander Prinzhorn - https://github.com/Prinzhorn/skrollr
*
* Free to use under terms of MIT license
*/
(function(document, window) {
'use strict';
var DEFAULT_DURATION = 500;
var DEFAULT_EASING = 'sqrt';
var DEFAULT_SCALE = 1;
var MENU_TOP_ATTR = 'data-menu-top';
var MENU_OFFSET_ATTR = 'data-menu-offset';
var MENU_DURATION_ATTR = 'data-menu-duration';
var MENU_IGNORE_ATTR = 'data-menu-ignore';
var skrollr = window.skrollr;
var history = window.history;
var supportsHistory = !!history.pushState;
/*
Since we are using event bubbling, the element that has been clicked
might not acutally be the link but a child.
*/
var findParentLink = function(element) {
//We reached the top, no link found.
if(element === document) {
return false;
}
//Yay, it's a link!
if(element.tagName.toUpperCase() === 'A') {
return element;
}
//Maybe the parent is a link.
return findParentLink(element.parentNode);
};
/*
Handle the click event on the document.
*/
var handleClick = function(e) {
//Only handle left click.
if(e.which !== 1 && e.button !== 0) {
return;
}
var link = findParentLink(e.target);
//The click did not happen inside a link.
if(!link) {
return;
}
if(handleLink(link)) {
e.preventDefault();
}
};
/*
Handles the click on a link. May be called without an actual click event.
When the fake flag is set, the link won't change the url and the position won't be animated.
*/
var handleLink = function(link, fake) {
var hash;
//When complexLinks is enabled, we also accept links which do not just contain a simple hash.
if(_complexLinks) {
//The link points to something completely different.
if(link.hostname !== window.location.hostname) {
return false;
}
//The link does not link to the same page/path.
if(link.pathname !== document.location.pathname) {
return false;
}
hash = link.hash;
} else {
//Don't use the href property (link.href) because it contains the absolute url.
hash = link.getAttribute('href');
}
//Not a hash link.
if(!/^#/.test(hash)) {
return false;
}
//The link has the ignore attribute.
if(!fake && link.getAttribute(MENU_IGNORE_ATTR) !== null) {
return false;
}
//Now get the targetTop to scroll to.
var targetTop;
var menuTop;
//If there's a handleLink function, it overrides the actual anchor offset.
if(_handleLink) {
menuTop = _handleLink(link);
}
//If there's a data-menu-top attribute and no handleLink function, it overrides the actual anchor offset.
else {
menuTop = link.getAttribute(MENU_TOP_ATTR);
}
if(menuTop !== null) {
//Is it a percentage offset?
if(/p$/.test(menuTop)) {
targetTop = (menuTop.slice(0, -1) / 100) * document.documentElement.clientHeight;
} else {
targetTop = +menuTop * _scale;
}
} else {
var scrollTarget = document.getElementById(hash.substr(1));
//Ignore the click if no target is found.
if(!scrollTarget) {
return false;
}
targetTop = _skrollrInstance.relativeToAbsolute(scrollTarget, 'top', 'top');
var menuOffset = scrollTarget.getAttribute(MENU_OFFSET_ATTR);
if(menuOffset !== null) {
targetTop += +menuOffset;
}
}
if(supportsHistory && _updateUrl && !fake) {
history.pushState({top: targetTop}, '', hash);
}
var menuDuration = parseInt(link.getAttribute(MENU_DURATION_ATTR), 10);
var animationDuration = _duration(_skrollrInstance.getScrollTop(), targetTop);
if(!isNaN(menuDuration)) {
animationDuration = menuDuration;
}
//Trigger the change if event if there's a listener.
if(_change) {
_change(hash, targetTop);
}
//Now finally scroll there.
if(_animate && !fake) {
_skrollrInstance.animateTo(targetTop, {
duration: animationDuration,
easing: _easing
});
} else {
defer(function() {
_skrollrInstance.setScrollTop(targetTop);
});
}
return true;
};
var jumpStraightToHash = function() {
if(window.location.hash && document.querySelector) {
var link = document.querySelector('a[href="' + window.location.hash + '"]');
if(!link) {
// No link found on page, so we create one and then activate it
link = document.createElement('a');
link.href = window.location.hash;
}
handleLink(link, true);
}
};
var defer = function(fn) {
window.setTimeout(fn, 1);
};
/*
Global menu function accessible through window.skrollr.menu.init.
*/
skrollr.menu = {};
skrollr.menu.init = function(skrollrInstance, options) {
_skrollrInstance = skrollrInstance;
options = options || {};
_easing = options.easing || DEFAULT_EASING;
_animate = options.animate !== false;
_duration = options.duration || DEFAULT_DURATION;
_handleLink = options.handleLink;
_scale = options.scale || DEFAULT_SCALE;
_complexLinks = options.complexLinks === true;
_change = options.change;
_updateUrl = options.updateUrl !== false;
if(typeof _duration === 'number') {
_duration = (function(duration) {
return function() {
return duration;
};
}(_duration));
}
//Use event bubbling and attach a single listener to the document.
skrollr.addEvent(document, 'click', handleClick);
if(supportsHistory) {
skrollr.addEvent(window, 'popstate', function(e) {
var state = e.state || {};
var top = state.top || 0;
defer(function() {
_skrollrInstance.setScrollTop(top);
});
}, false);
}
jumpStraightToHash();
};
//Expose the handleLink function to be able to programmatically trigger clicks.
skrollr.menu.click = function(link) {
//We're not assigning it directly to `click` because of the second ("private") parameter.
handleLink(link);
};
//Private reference to the initialized skrollr.
var _skrollrInstance;
var _easing;
var _duration;
var _animate;
var _handleLink;
var _scale;
var _complexLinks;
var _change;
var _updateUrl;
//In case the page was opened with a hash, prevent jumping to it.
//http://stackoverflow.com/questions/3659072/jquery-disable-anchor-jump-when-loading-a-page
defer(function() {
if(window.location.hash) {
window.scrollTo(0, 0);
}
});
}(document, window));
The problem was the easing function found here
//Now finally scroll there.
if(_animate && !fake) {
_skrollrInstance.animateTo(targetTop, {
duration: animationDuration,
easing: _easing
});
} else {
defer(function() {
_skrollrInstance.setScrollTop(targetTop);
});
}
return true;
It seems that, even though Skrollr states that easing's default is linear (no easing), the default is ACTUALLY set to sqrt (or at least it was in my case). The problem can be solved by forcing easing to linear in skrollr.menu.init, or chaning the skrollr.menu.js file to remove easing from the function. The first of these two solutions is cleaner, and won't cause issues later.
skrollr.menu.init(s, {
duration: function(currentTop, targetTop) {return 20000;},
easing: 'linear'
});

jQuery cookie key value with case statement

Ok, so my code is this so far:
$( document ).ready(function() {
// setup the initial display on page load
var menu_state = $.cookie('atd_gridlist');
// listen for the clicks
$('.gridselect').click(function() {
$.cookie('atd_gridlist', 'grid'); // update (or set) the cookie
$(".grid").css("display", "block");
$(".list").css("display", "none");
});
$('.listselect').click(function() {
$.cookie('atd_gridlist', 'list'); // update (or set) the cookie
$(".grid").css("display", "none");
$(".list").css("display", "block");
});
});
I need to also check to see if the cookie KEY has already been set, I think a case statement would work but I am not sure how to make the case read just the cookie atd_gridlist key values...
If it is gridselect I need to show the grid div and hide the list div, if it is listselect I need it to show the list div and hide the grid div, if it is not set at all, I want grid div loaded by default and hide the list. I also would like to expire the div every 7 days.
Any help in the right direction is appreciated. Thanks!
Would something like this do the job?
$(function() {
var grid = $('.grid');
var list = $('.list');
var stateCookie = 'atd_gridlist';
var SetStateCookie = function(value) {
$.cookie(stateCookie, value, { expires: 7, path: '/' });
}
var ShowByState = function(state) {
state = state || 'grid';
SetStateCookie(state);
if ('grid' === state) {
grid.show();
list.hide();
} else if ('list' === state) {
grid.hide();
list.show();
}
}
$('.gridselect').click(function() {
ShowByState('grid');
});
$('.listselect').click(function() {
ShowByState('list');
});
ShowByState($.cookie(stateCookie));
});

Sequentially fade in divs on coming into view with jQuery

I'm currently using jquery.inview to detect when certain elements are fully visible in the browser. I have this working correctly like so:
$('.exclusive').bind('inview',function(e, isInView, visiblePartX, visiblePartY) {
var elem = $(this);
if (elem.data('inviewtimer')) {
clearTimeout(elem.data('inviewtimer'));
elem.removeData('inviewtimer');
}
if (isInView) {
elem.data('inviewtimer', setTimeout(function() {
if (visiblePartY == 'top') {
elem.data('seenTop', true);
} else if (visiblePartY == 'bottom') {
elem.data('seenBottom', true);
} else {
elem.data('seenTop', true);
elem.data('seenBottom', true);
}
if (elem.data('seenTop') && elem.data('seenBottom')) {
elem.animate({ 'opacity' : 1}, 1000)
elem.unbind('inview');
}
}, 1000))
}
});
However, I want to amend this code slightly, so that when there are multiple matched elements in view, these are faded in sequentially with a slight delay between each. And of course when the user moves the viewport to bring more elements into view it will continue to do the same. Can anyone point me in the right direction?
Thanks,
Chris
You can delay fading in of particular elements like this:
var divs = $('div'); // replace with your selector
$.each(divs, function(i, item) {
setTimeout(function() {
$(item).fadeIn(1000);
}, 1000 * i);
});​
Check the live DEMO.

Hover state of element

I have div if i mouse over on div i need to call a handler and show hover card of user
my problem is when handler is running if i mouse out
but still am getting my hover card
this shouldn't happen
Is there any way in javascript i can know wheather element have hover state are not
showPopup: function() {
moLikeDisLikeUsers.popup = 'show';
var url = '/_service/getHoverCardDetails.ashx';
var pars = Object.toQueryString({ 'prfid': moLikeDisLikeUsers.options.get('profileid'), 'id': moLikeDisLikeUsers.options.get('profileid'), 'ht': "1" });
var target = 'output-div';
if (Object.isUndefined(userkey.get(moLikeDisLikeUsers.options.get('profileid'))) || (userkey.get(moLikeDisLikeUsers.options.get('profileid'))) == '') {
moLikeDisLikeUsers.ajax = new Ajax.Updater(target, url, { method: 'get', parameters: pars, onSuccess: function(transport) {
var response = transport.responseText || "no response text";
var data = transport.responseText.evalJSON(true);
userkey.set(moLikeDisLikeUsers.options.get('profileid'), data);
if (moLikeDisLikeUsers.popup == 'show') {
moLikeDisLikeUsers.drawPopup(data);
}
}
});
}
else {
moLikeDisLikeUsers.drawPopup(userkey.get(moLikeDisLikeUsers.options.get('profileid')));
}
},
hidetip: function() {
if (moLikeDisLikeUsers.tooltip) {
AbortAjaxCall(moLikeDisLikeUsers.ajax);
moLikeDisLikeUsers.popup = 'hidden';
moLikeDisLikeUsers.tooltip.hide();
}
},
I imagine you could use getComputedStyle to figure out what the value of a property was on an element, and change it with an external stylesheet (defining different rules for #foo and #foo:hover), but you are probably better off writing logic that does the right thing (whatever that might be) when the mouseover and mouseout events fire.
Better yet, don't show content on :hover.

setInterval with other jQuery events - Too many recursions

I'm trying to build a Javascript listener for a small page that uses AJAX to load content based on the anchor in the URL. Looking online, I found and modified a script that uses setInterval() to do this and so far it works fine. However, I have other jQuery elements in the $(document).ready() for special effects for the menus and content. If I use setInterval() no other jQuery effects work. I finagled a way to get it work by including the jQuery effects in the loop for setInterval() like so:
$(document).ready(function() {
var pageScripts = function() {
pageEffects();
pageURL();
}
window.setInterval(pageScripts, 500);
});
var currentAnchor = null;
function pageEffects() {
// Popup Menus
$(".bannerMenu").hover(function() {
$(this).find("ul.bannerSubmenu").slideDown(300).show;
}, function() {
$(this).find("ul.bannerSubmenu").slideUp(400);
});
$(".panel").hover(function() {
$(this).find(".panelContent").fadeIn(200);
}, function() {
$(this).find(".panelContent").fadeOut(300);
});
// REL Links Control
$("a[rel='_blank']").click(function() {
this.target = "_blank";
});
$("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
$("#content").fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
}
}
This works fine for a while but after a few minutes of the page being loaded, it drags to a near stop in IE and Firefox. I checked the FF Error Console and it comes back with an error "Too many Recursions." Chrome seems to not care and the page continues to run more or less normally despite the amount of time it's been open.
It would seem to me that the pageEffects() call is causing the issue with the recursion, however, any attempts to move it out of the loop breaks them and they cease to work as soon as setInterval makes it first loop.
Any help on this would be greatly appreciated!
I am guessing that the pageEffects need added to the pageURL content.
At the very least this should be more efficient and prevent duplicate handlers
$(document).ready(function() {
pageEffects($('body'));
(function(){
pageURL();
window.setTimeout(arguments.callee, 500);
})();
});
var currentAnchor = null;
function pageEffects(parent) {
// Popup Menus
parent.find(".bannerMenu").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
subMenu: $(this).find("ul.bannerSubmenu"),
handlerIn: function() {
this.subMenu.slideDown(300).show();
},
handlerOut: function() {
this.subMenu.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
parent.find(".panel").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
content: panel.find(".panelContent"),
handlerIn: function() {
this.content.fadeIn(200).show();
},
handlerOut: function() {
this.content.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
// REL Links Control
parent.find("a[rel='_blank']").each(function() {
$(this).target = "_blank";
});
parent.find("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
var content = $("#content");
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
content.fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
pageEffects(content);
}
}
Thanks for the suggestions. I tried a few of them and they still did not lead to the desirable effects. After some cautious testing, I found out what was happening. With jQuery (and presumably Javascript as a whole), whenever an AJAX callback is made, the elements brought in through the callback are not binded to what was originally binded in the document, they must be rebinded. You can either do this by recalling all the jQuery events on a successful callback or by using the .live() event in jQuery's library. I opted for .live() and it works like a charm now and no more recursive errors :D.
$(document).ready(function() {
// Popup Menus
$(".bannerMenu").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find("ul.bannerSubmenu").slideDown(300);
} else {
$(this).find("ul.bannerSubmenu").slideUp(400);
}
});
// Rollover Content
$(".panel").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find(".panelContent").fadeIn(200);
} else {
$(this).find(".panelContent").fadeOut(300);
}
});
// HREF Events
$("a[rel='_blank']").live("click", function(event) {
var target = $(this).attr("href");
window.open(target, "_blank");
event.preventDefault();
});
$("a[rel='share']").live("click", function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
setInterval("checkAnchor()", 500);
});
var currentAnchor = null;
function checkAnchor() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn(200);
$("#content").fadeOut(200).html(data).fadeIn(200);
$("#load").fadeOut(200);
});
}
}
Anywho, the page works as intended even in IE (which I rarely check for compatibility). Hopefully, some other newb will learn from my mistakes :p.

Categories