Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: stevenbenner/jquery-powertip
base: v1.0.0
...
head fork: stevenbenner/jquery-powertip
compare: v1.0.1
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 1 file changed
  • 0 commit comments
  • 1 contributor
Showing with 85 additions and 17 deletions.
  1. +85 −17 jquery.powertip.js
View
102 jquery.powertip.js
@@ -4,7 +4,7 @@
* @fileoverview jQuery plugin that creates hover tooltips.
* @link https://github.com/stevenbenner/jquery-powertip
* @author Steven Benner
- * @version 1.0
+ * @version 1.0.1
* @requires jQuery 1.7 or later
* @license jQuery PowerTip Plugin
* <https://github.com/stevenbenner/jquery-powertip>
@@ -28,14 +28,14 @@
var session = {
isPopOpen: false,
isFixedPopOpen: false,
- isMouseConstatnlyTracked: false,
popOpenImminent: false,
activeHover: null,
mouseTarget: null,
currentX: 0,
currentY: 0,
previousX: 0,
- previousY: 0
+ previousY: 0,
+ desyncTimeout: null
};
/**
@@ -53,6 +53,9 @@
// extend options
var options = $.extend({}, $.fn.powerTip.defaults, opts);
+ // hook mouse tracking, once
+ hookOnMoveOnce();
+
// build and append popup div if it does not already exist
var tipElement = $('#' + options.popupId);
if (tipElement.length === 0) {
@@ -60,14 +63,12 @@
$body.append(tipElement);
}
- // because of the intent delay we need to constantly track the cursor
- // position for mouse-follow powertips
+ // hook mousemove for cursor follow tooltips
if (options.followMouse) {
// only one movePop hook per popup element, please
if (!tipElement.data('hasMouseMove')) {
$window.on('mousemove', movePop);
}
- session.isMouseConstatnlyTracked = true;
tipElement.data('hasMouseMove', true);
}
@@ -116,9 +117,6 @@
session.mouseTarget = element;
session.previousX = event.pageX;
session.previousY = event.pageY;
- if (!session.isMouseConstatnlyTracked) {
- element.on('mousemove', trackMouse);
- }
if (!element.data('hasActiveHover')) {
session.popOpenImminent = true;
setHoverTimer(element, 'show');
@@ -128,9 +126,6 @@
var element = $(this);
cancelHoverTimer(element);
session.mouseTarget = null;
- if (!session.isMouseConstatnlyTracked) {
- element.off('mousemove', trackMouse);
- }
session.popOpenImminent = false;
if (element.data('hasActiveHover')) {
setHoverTimer(element, 'hide');
@@ -155,9 +150,6 @@
// check if difference has passed the sensitivity threshold
if (totalDifference < options.intentSensitivity) {
- if (!session.isMouseConstatnlyTracked) {
- element.off('mousemove', trackMouse);
- }
element.data('hasActiveHover', true);
// show popup, asap
showTip(element);
@@ -215,7 +207,12 @@
tipElement.data('mouseOnToPopup', options.mouseOnToPopup);
// fadein
- tipElement.stop(true, true).fadeIn(options.fadeInTime);
+ tipElement.stop(true, true).fadeIn(options.fadeInTime, function() {
+ // start desync polling
+ if (!session.desyncTimeout) {
+ session.desyncTimeout = setInterval(closeDesyncedTip, 500);
+ }
+ });
}
/**
@@ -234,10 +231,55 @@
// after it is hidden
tipElement.css('left', session.currentX + options.offset + 'px');
tipElement.css('top', session.currentY + options.offset + 'px');
+ // stop desync polling
+ session.desyncTimeout = clearInterval(session.desyncTimeout);
});
}
/**
+ * Checks for a tooltip desync and closes the tooltip if one occurs.
+ * @private
+ */
+ function closeDesyncedTip() {
+ // It is possible for the mouse cursor to leave an element without
+ // firing the mouseleave event. This seems to happen (in FF) if the
+ // element is disabled under mouse cursor, the element is moved out
+ // from under the mouse cursor (such as a slideDown() occurring
+ // above it), or if the browser is resized by code moving the
+ // element from under the mouse cursor. If this happens it will
+ // result in a desynced tooltip because we wait for any exiting
+ // open tooltips to close before opening a new one. So we should
+ // periodically check for a desync situation and close the tip if
+ // such a situation arises.
+ if (session.isPopOpen) {
+ var isDesynced = false;
+
+ // case 1: user already moused onto another tip - easy test
+ if (session.activeHover.data('hasActiveHover') === false) {
+ isDesynced = true;
+ } else {
+ // case 2: hanging tip - have to test if mouse position is
+ // not over the active hover and not over a tooltip set to
+ // let the user interact with it
+ if (!isMouseOver(session.activeHover)) {
+ if (tipElement.data('mouseOnToPopup')) {
+ if (!isMouseOver(tipElement)) {
+ isDesynced = true;
+ }
+ } else {
+ isDesynced = true;
+ }
+ }
+ }
+
+ if (isDesynced) {
+ // close the desynced tip
+ hideTip(session.activeHover);
+ }
+ }
+ }
+
+ /**
* Moves the tooltip popup to the users mouse cursor.
* @private
* @param {Object} event The window or document mousemove event.
@@ -249,7 +291,6 @@
// but we should only set the pop location if a fixed pop is not
// currently open, a pop open is imminent or active, and the popup
// element in question does have a mouse-follow using it.
- trackMouse(event);
if ((session.isPopOpen && !session.isFixedPopOpen) || (session.popOpenImminent && !session.isFixedPopOpen && tipElement.data('hasMouseMove'))) {
// grab measurements
var scrollTop = $window.scrollTop(),
@@ -364,6 +405,19 @@
mouseOnToPopup: false
};
+ var onMoveHooked = false;
+ /**
+ * Hooks the trackMouse() function to the window's mousemove event.
+ * Prevents attaching the event more than once.
+ * @private
+ */
+ function hookOnMoveOnce() {
+ if (!onMoveHooked) {
+ onMoveHooked = true;
+ $window.on('mousemove', trackMouse);
+ }
+ }
+
/**
* Saves the current mouse coordinates to the powerTip session object.
* @private
@@ -386,4 +440,18 @@
}
}
+ /**
+ * Tests if the mouse is currently over the specified element.
+ * @private
+ * @param {Object} element The element to check for hover.
+ * @return {Boolean}
+ */
+ function isMouseOver(element) {
+ var elementPosition = element.offset();
+ return session.currentX >= elementPosition.left &&
+ session.currentX <= elementPosition.left + element.outerWidth() &&
+ session.currentY >= elementPosition.top &&
+ session.currentY <= elementPosition.top + element.outerHeight();
+ }
+
}(jQuery));

No commit comments for this range

Something went wrong with that request. Please try again.