diff --git a/package.json b/package.json index b26a914b4..059034f23 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "one-light-syntax": "1.6.0", "solarized-dark-syntax": "1.1.1", "solarized-light-syntax": "1.1.1", - "about": "1.7.0", + "about": "1.7.1", "archive-view": "0.62.0", "autocomplete-atom-api": "0.10.0", "autocomplete-css": "0.14.1", diff --git a/spec/tooltip-manager-spec.coffee b/spec/tooltip-manager-spec.coffee index 6bebd6e76..a7e8ccb1f 100644 --- a/spec/tooltip-manager-spec.coffee +++ b/spec/tooltip-manager-spec.coffee @@ -1,4 +1,6 @@ +{CompositeDisposable} = require 'atom' TooltipManager = require '../src/tooltip-manager' +Tooltip = require '../src/tooltip' _ = require 'underscore-plus' describe "TooltipManager", -> @@ -9,17 +11,27 @@ describe "TooltipManager", -> beforeEach -> manager = new TooltipManager(keymapManager: atom.keymaps, viewRegistry: atom.views) - element = document.createElement('div') - element.classList.add('foo') - jasmine.attachToDOM(element) + element = createElement 'foo' - hover = (element, fn) -> + createElement = (className) -> + el = document.createElement('div') + el.classList.add(className) + jasmine.attachToDOM(el) + el + + mouseEnter = (element) -> element.dispatchEvent(new CustomEvent('mouseenter', bubbles: false)) element.dispatchEvent(new CustomEvent('mouseover', bubbles: true)) - advanceClock(manager.hoverDefaults.delay.show) - fn() + + mouseLeave = (element) -> element.dispatchEvent(new CustomEvent('mouseleave', bubbles: false)) element.dispatchEvent(new CustomEvent('mouseout', bubbles: true)) + + hover = (element, fn) -> + mouseEnter(element) + advanceClock(manager.hoverDefaults.delay.show) + fn() + mouseLeave(element) advanceClock(manager.hoverDefaults.delay.hide) describe "::add(target, options)", -> @@ -29,6 +41,32 @@ describe "TooltipManager", -> hover element, -> expect(document.body.querySelector(".tooltip")).toHaveText("Title") + it "displays tooltips immediately when hovering over new elements once a tooltip has been displayed once", -> + disposables = new CompositeDisposable + element1 = createElement('foo') + disposables.add(manager.add element1, title: 'Title') + element2 = createElement('bar') + disposables.add(manager.add element2, title: 'Title') + element3 = createElement('baz') + disposables.add(manager.add element3, title: 'Title') + + hover element1, -> + expect(document.body.querySelector(".tooltip")).toBeNull() + + mouseEnter(element2) + expect(document.body.querySelector(".tooltip")).not.toBeNull() + mouseLeave(element2) + advanceClock(manager.hoverDefaults.delay.hide) + expect(document.body.querySelector(".tooltip")).toBeNull() + + advanceClock(Tooltip.FOLLOW_THROUGH_DURATION) + mouseEnter(element3) + expect(document.body.querySelector(".tooltip")).toBeNull() + advanceClock(manager.hoverDefaults.delay.show) + expect(document.body.querySelector(".tooltip")).not.toBeNull() + + disposables.dispose() + describe "when the trigger is 'manual'", -> it "creates a tooltip immediately and only hides it on dispose", -> disposable = manager.add element, title: "Title", trigger: "manual" @@ -149,6 +187,6 @@ describe "TooltipManager", -> it "hides the tooltips", -> manager.add element, title: "Title" hover element, -> - expect(document.body.querySelector(".tooltip")).toBeDefined() + expect(document.body.querySelector(".tooltip")).not.toBeNull() window.dispatchEvent(new CustomEvent('resize')) expect(document.body.querySelector(".tooltip")).toBeNull() diff --git a/src/tooltip.js b/src/tooltip.js index f0f9d1a3f..2573b1fb9 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -7,6 +7,8 @@ const listen = require('./delegated-listener') // This tooltip class is derived from Bootstrap 3, but modified to not require // jQuery, which is an expensive dependency we want to eliminate. +var followThroughTimer = null + var Tooltip = function (element, options, viewRegistry) { this.options = null this.enabled = null @@ -21,7 +23,7 @@ var Tooltip = function (element, options, viewRegistry) { Tooltip.VERSION = '3.3.5' -Tooltip.TRANSITION_DURATION = 150 +Tooltip.FOLLOW_THROUGH_DURATION = 300 Tooltip.DEFAULTS = { animation: true, @@ -151,7 +153,11 @@ Tooltip.prototype.enter = function (event) { this.hoverState = 'in' - if (!this.options.delay || !this.options.delay.show) return this.show() + if (!this.options.delay || + !this.options.delay.show || + followThroughTimer) { + return this.show() + } this.timeout = setTimeout(function () { if (this.hoverState === 'in') this.show() @@ -343,6 +349,14 @@ Tooltip.prototype.hide = function (callback) { this.hoverState = null + clearTimeout(followThroughTimer) + followThroughTimer = setTimeout( + function () { + followThroughTimer = null + }, + Tooltip.FOLLOW_THROUGH_DURATION + ) + return this }