From ef3c0576656e3d01c24df0b3f68fe41631147c98 Mon Sep 17 00:00:00 2001 From: Shane Tomlinson <stomlinson@mozilla.com> Date: Mon, 6 Aug 2012 14:17:47 +0100 Subject: [PATCH] Make sure only one is ever shown at a time. Some further cleanup because tooltip code was fugly. --- resources/static/common/js/tooltip.js | 114 +++++++++--------- .../static/test/cases/common/js/tooltip.js | 40 +++--- 2 files changed, 75 insertions(+), 79 deletions(-) diff --git a/resources/static/common/js/tooltip.js b/resources/static/common/js/tooltip.js index e50d8bc89..673c64dc6 100644 --- a/resources/static/common/js/tooltip.js +++ b/resources/static/common/js/tooltip.js @@ -8,24 +8,23 @@ BrowserID.Tooltip = (function() { "use strict"; var ANIMATION_TIME = 250, - TOOLTIP_DISPLAY = 2000, + TOOLTIP_MIN_DISPLAY = 2000, READ_WPM = 200, bid = BrowserID, - dom = bid.DOM, renderer = bid.Renderer, - hideTimer; + hideTimer, + tooltip; function createTooltip(el) { - var contents = el.html(); - - var tooltip = renderer.append("body", "tooltip", { - contents: contents - }); + tooltip = renderer.append("body", "tooltip", { + contents: el.html() + }); - return tooltip; + return tooltip; } - function positionTooltip(tooltip, target) { + function anchorTooltip(target) { + target = $(target); var targetOffset = target.offset(); targetOffset.top -= (tooltip.outerHeight() + 5); targetOffset.left += 10; @@ -33,56 +32,69 @@ BrowserID.Tooltip = (function() { tooltip.css(targetOffset); } - function animateTooltip(el, complete) { - var contents = el.text().replace(/\s+/, ' ').replace(/^\s+/, '').replace(/\s+$/, ''); - var words = contents.split(' ').length; + function calculateDisplayTime(text) { + // Calculate the amount of time a tooltip should display based on the + // number of words in the content divided by the number of words an average + // person can read per minute. + var contents = text.replace(/\s+/, ' ').trim(), + words = contents.split(' ').length, + // The average person can read ± 250 wpm. + wordTimeMS = (words / READ_WPM) * 60 * 1000, + displayTimeMS = Math.max(wordTimeMS, TOOLTIP_MIN_DISPLAY); + + return displayTimeMS; + } - // The average person can read ± 250 wpm. - var wordTimeMS = (words / READ_WPM) * 60 * 1000; - var displayTimeMS = Math.max(wordTimeMS, TOOLTIP_DISPLAY); + function animateTooltip(el, complete) { + var displayTimeMS = calculateDisplayTime(el.text()); bid.Tooltip.shown = true; el.fadeIn(ANIMATION_TIME, function() { hideTimer = setTimeout(function() { - el.fadeOut(ANIMATION_TIME, function() { - bid.Tooltip.shown = false; - if(complete) complete(); - }); + el.fadeOut(ANIMATION_TIME, complete); }, displayTimeMS); }); - } - function createAndShowRelatedTooltip(el, relatedTo, complete) { - // This means create a copy of the tooltip element and position it in - // relation to an element. Right now we are putting the tooltip directly - // above the element. Once the tooltip is no longer needed, remove it - // from the DOM. - var tooltip = createTooltip(el); - - var target = $("#" + relatedTo); - positionTooltip(tooltip, target); - - animateTooltip(tooltip, function() { - if (tooltip) { - tooltip.remove(); - tooltip = null; - } - if (complete) complete(); - }); + return displayTimeMS; } function showTooltip(el, complete) { - el = $(el); - var messageFor = el.attr("for"); + // Only one tooltip can be shown at a time, see issue #1615 + removeTooltips(); + + // By default, the element passed in is the tooltip element. If it has + // a "for" attribute, that means this tooltip should be anchored to the + // element listed in the "for" attribute. If that is the case, create a new + // tooltip and anchor it to the other element. + var tooltipEl = $(el), + tooltipAnchor = tooltipEl.attr("for"); + + if (tooltipAnchor) { + // The tooltip should be anchored to another element. Place the tooltip + // directly above the element and remove it when it is no longer needed. + tooltipEl = createTooltip(tooltipEl); + anchorTooltip("#" + tooltipAnchor); + } + + return animateTooltip(tooltipEl, function() { + removeTooltips(); + complete && complete(); + }); + } - // First, see if we are "for" another element, if we are, create a copy of - // the tooltip to attach to the element. - if(messageFor) { - createAndShowRelatedTooltip(el, messageFor, complete); + function removeTooltips() { + if (tooltip) { + tooltip.remove(); + tooltip = null; } - else { - animateTooltip(el, complete); + + if (hideTimer) { + clearTimeout(hideTimer); + hideTimer = null; } + + $('.tooltip').hide(); + bid.Tooltip.shown = false; } @@ -90,15 +102,7 @@ BrowserID.Tooltip = (function() { showTooltip: showTooltip // BEGIN TESTING API , - reset: function() { - if(hideTimer) { - clearTimeout(hideTimer); - hideTimer = null; - } - - $(".tooltip").hide(); - bid.Tooltip.shown = false; - } + reset: removeTooltips // END TESTING API }; diff --git a/resources/static/test/cases/common/js/tooltip.js b/resources/static/test/cases/common/js/tooltip.js index e084eb511..81df7ad02 100644 --- a/resources/static/test/cases/common/js/tooltip.js +++ b/resources/static/test/cases/common/js/tooltip.js @@ -7,42 +7,28 @@ "use strict"; var bid = BrowserID, - tooltip = bid.Tooltip + tooltip = bid.Tooltip, + testHelpers = bid.TestHelpers; module("common/js/tooltip", { setup: function() { + testHelpers.setup(); }, teardown: function() { + testHelpers.teardown(); } }); - asyncTest("show short tooltip, min of 2.5 seconds", function() { - var startTime = new Date().getTime(); - - tooltip.showTooltip("#shortTooltip", function() { - var endTime = new Date().getTime(); - var diff = endTime - startTime; - ok(2000 <= diff && diff <= 3000, diff + " - minimum of 2 seconds, max of 3 seconds"); - - equal(tooltip.shown, false, "tooltip says it is no longer shown"); - - start(); - }); - + test("show short tooltip - shows for about 2.5 seconds", function() { + var displayTime = tooltip.showTooltip("#shortTooltip"); + ok(2000 <= displayTime && displayTime <= 3000, displayTime + " - minimum of 2 seconds, max of 3 seconds"); equal(tooltip.shown, true, "tooltip says that it is shown"); }); - asyncTest("show long tooltip, takes about 5 seconds", function() { - var startTime = new Date().getTime(); - - tooltip.showTooltip("#longTooltip", function() { - var endTime = new Date().getTime(); - var diff = endTime - startTime; - ok(diff >= 4500, diff + " - longer tooltip is on the screen for a bit longer"); - - start(); - }); + test("show long tooltip - shows for about 5 seconds", function() { + var displayTime = tooltip.showTooltip("#longTooltip"); + ok(displayTime >= 4500, displayTime + " - longer tooltip is on the screen for a bit longer"); }); asyncTest("show tooltip, then reset - hides tooltip, resets shown status", function() { @@ -56,4 +42,10 @@ }, 100); }); + test("only one tooltip shown at a time", function() { + tooltip.showTooltip("#shortTooltip"); + tooltip.showTooltip("#shortTooltip"); + equal($(".tooltip:visible").length, 1, "only one tooltip shown at a time"); + }); + }()); -- GitLab