123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- // Copyright 2007 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /**
- * @fileoverview Advanced tooltip widget implementation.
- *
- * @author eae@google.com (Emil A Eklund)
- * @see ../demos/advancedtooltip.html
- */
- goog.provide('goog.ui.AdvancedTooltip');
- goog.require('goog.events');
- goog.require('goog.events.EventType');
- goog.require('goog.math.Box');
- goog.require('goog.math.Coordinate');
- goog.require('goog.style');
- goog.require('goog.ui.Tooltip');
- goog.require('goog.userAgent');
- /**
- * Advanced tooltip widget with cursor tracking abilities. Works like a regular
- * tooltip but can track the cursor position and direction to determine if the
- * tooltip should be dismissed or remain open.
- *
- * @param {Element|string=} opt_el Element to display tooltip for, either
- * element reference or string id.
- * @param {?string=} opt_str Text message to display in tooltip.
- * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
- * @constructor
- * @extends {goog.ui.Tooltip}
- */
- goog.ui.AdvancedTooltip = function(opt_el, opt_str, opt_domHelper) {
- goog.ui.Tooltip.call(this, opt_el, opt_str, opt_domHelper);
- };
- goog.inherits(goog.ui.AdvancedTooltip, goog.ui.Tooltip);
- goog.tagUnsealableClass(goog.ui.AdvancedTooltip);
- /**
- * Whether to track the cursor and thereby close the tooltip if it moves away
- * from the tooltip and keep it open if it moves towards it.
- *
- * @type {boolean}
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.cursorTracking_ = false;
- /**
- * Delay in milliseconds before tooltips are hidden if cursor tracking is
- * enabled and the cursor is moving away from the tooltip.
- *
- * @type {number}
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.cursorTrackingHideDelayMs_ = 100;
- /**
- * Box object representing a margin around the tooltip where the cursor is
- * allowed without dismissing the tooltip.
- *
- * @type {goog.math.Box}
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.hotSpotPadding_;
- /**
- * Bounding box.
- *
- * @type {goog.math.Box}
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.boundingBox_;
- /**
- * Anchor bounding box.
- *
- * @type {goog.math.Box}
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.anchorBox_;
- /**
- * Whether the cursor tracking is active.
- *
- * @type {boolean}
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.tracking_ = false;
- /**
- * Sets margin around the tooltip where the cursor is allowed without dismissing
- * the tooltip.
- *
- * @param {goog.math.Box=} opt_box The margin around the tooltip.
- */
- goog.ui.AdvancedTooltip.prototype.setHotSpotPadding = function(opt_box) {
- this.hotSpotPadding_ = opt_box || null;
- };
- /**
- * @return {goog.math.Box} box The margin around the tooltip where the cursor is
- * allowed without dismissing the tooltip.
- */
- goog.ui.AdvancedTooltip.prototype.getHotSpotPadding = function() {
- return this.hotSpotPadding_;
- };
- /**
- * Sets whether to track the cursor and thereby close the tooltip if it moves
- * away from the tooltip and keep it open if it moves towards it.
- *
- * @param {boolean} b Whether to track the cursor.
- */
- goog.ui.AdvancedTooltip.prototype.setCursorTracking = function(b) {
- this.cursorTracking_ = b;
- };
- /**
- * @return {boolean} Whether to track the cursor and thereby close the tooltip
- * if it moves away from the tooltip and keep it open if it moves towards
- * it.
- */
- goog.ui.AdvancedTooltip.prototype.getCursorTracking = function() {
- return this.cursorTracking_;
- };
- /**
- * Sets delay in milliseconds before tooltips are hidden if cursor tracking is
- * enabled and the cursor is moving away from the tooltip.
- *
- * @param {number} delay The delay in milliseconds.
- */
- goog.ui.AdvancedTooltip.prototype.setCursorTrackingHideDelayMs = function(
- delay) {
- this.cursorTrackingHideDelayMs_ = delay;
- };
- /**
- * @return {number} The delay in milliseconds before tooltips are hidden if
- * cursor tracking is enabled and the cursor is moving away from the
- * tooltip.
- */
- goog.ui.AdvancedTooltip.prototype.getCursorTrackingHideDelayMs = function() {
- return this.cursorTrackingHideDelayMs_;
- };
- /**
- * Called after the popup is shown.
- * @protected
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.onShow = function() {
- goog.ui.AdvancedTooltip.superClass_.onShow.call(this);
- this.boundingBox_ = goog.style.getBounds(this.getElement()).toBox();
- if (this.anchor) {
- this.anchorBox_ = goog.style.getBounds(this.anchor).toBox();
- }
- this.tracking_ = this.cursorTracking_;
- goog.events.listen(
- this.getDomHelper().getDocument(), goog.events.EventType.MOUSEMOVE,
- this.handleMouseMove, false, this);
- };
- /**
- * Called after the popup is hidden.
- * @protected
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.onHide = function() {
- goog.events.unlisten(
- this.getDomHelper().getDocument(), goog.events.EventType.MOUSEMOVE,
- this.handleMouseMove, false, this);
- this.boundingBox_ = null;
- this.anchorBox_ = null;
- this.tracking_ = false;
- goog.ui.AdvancedTooltip.superClass_.onHide.call(this);
- };
- /**
- * Returns true if the mouse is in the tooltip.
- * @return {boolean} True if the mouse is in the tooltip.
- */
- goog.ui.AdvancedTooltip.prototype.isMouseInTooltip = function() {
- return this.isCoordinateInTooltip(this.cursorPosition);
- };
- /**
- * Checks whether the supplied coordinate is inside the tooltip, including
- * padding if any.
- * @param {goog.math.Coordinate} coord Coordinate being tested.
- * @return {boolean} Whether the coord is in the tooltip.
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.isCoordinateInTooltip = function(coord) {
- // Check if coord is inside the bounding box of the tooltip
- if (this.hotSpotPadding_) {
- var offset = goog.style.getPageOffset(this.getElement());
- var size = goog.style.getSize(this.getElement());
- return offset.x - this.hotSpotPadding_.left <= coord.x &&
- coord.x <= offset.x + size.width + this.hotSpotPadding_.right &&
- offset.y - this.hotSpotPadding_.top <= coord.y &&
- coord.y <= offset.y + size.height + this.hotSpotPadding_.bottom;
- }
- return goog.ui.AdvancedTooltip.superClass_.isCoordinateInTooltip.call(
- this, coord);
- };
- /**
- * Checks if supplied coordinate is in the tooltip, its triggering anchor, or
- * a tooltip that has been triggered by a child of this tooltip.
- * Called from handleMouseMove to determine if hide timer should be started,
- * and from maybeHide to determine if tooltip should be hidden.
- * @param {goog.math.Coordinate} coord Coordinate being tested.
- * @return {boolean} Whether coordinate is in the anchor, the tooltip, or any
- * tooltip whose anchor is a child of this tooltip.
- * @private
- */
- goog.ui.AdvancedTooltip.prototype.isCoordinateActive_ = function(coord) {
- if ((this.anchorBox_ && this.anchorBox_.contains(coord)) ||
- this.isCoordinateInTooltip(coord)) {
- return true;
- }
- // Check if mouse might be in active child element.
- var childTooltip = this.getChildTooltip();
- return !!childTooltip && childTooltip.isCoordinateInTooltip(coord);
- };
- /**
- * Called by timer from mouse out handler. Hides tooltip if cursor is still
- * outside element and tooltip.
- * @param {?Element|undefined} el Anchor when hide timer was started.
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.maybeHide = function(el) {
- this.hideTimer = undefined;
- if (el == this.anchor) {
- // Check if cursor is inside the bounding box of the tooltip or the element
- // that triggered it, or if tooltip is active (possibly due to receiving
- // the focus), or if there is a nested tooltip being shown.
- if (!this.isCoordinateActive_(this.cursorPosition) &&
- !this.getActiveElement() && !this.hasActiveChild()) {
- // Under certain circumstances gecko fires ghost mouse events with the
- // coordinates 0, 0 regardless of the cursors position.
- if (goog.userAgent.GECKO && this.cursorPosition.x == 0 &&
- this.cursorPosition.y == 0) {
- return;
- }
- this.setVisible(false);
- }
- }
- };
- /**
- * Handler for mouse move events.
- *
- * @param {goog.events.BrowserEvent} event Event object.
- * @protected
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.handleMouseMove = function(event) {
- var startTimer = this.isVisible();
- if (this.boundingBox_) {
- var scroll = this.getDomHelper().getDocumentScroll();
- var c = new goog.math.Coordinate(
- event.clientX + scroll.x, event.clientY + scroll.y);
- if (this.isCoordinateActive_(c)) {
- startTimer = false;
- } else if (this.tracking_) {
- var prevDist =
- goog.math.Box.distance(this.boundingBox_, this.cursorPosition);
- var currDist = goog.math.Box.distance(this.boundingBox_, c);
- startTimer = currDist >= prevDist;
- }
- }
- if (startTimer) {
- this.startHideTimer();
- // Even though the mouse coordinate is not on the tooltip (or nested child),
- // they may have an active element because of a focus event. Don't let
- // that prevent us from taking down the tooltip(s) on this mouse move.
- this.setActiveElement(null);
- var childTooltip = this.getChildTooltip();
- if (childTooltip) {
- childTooltip.setActiveElement(null);
- }
- } else if (this.getState() == goog.ui.Tooltip.State.WAITING_TO_HIDE) {
- this.clearHideTimer();
- }
- goog.ui.AdvancedTooltip.superClass_.handleMouseMove.call(this, event);
- };
- /**
- * Handler for mouse over events for the tooltip element.
- *
- * @param {goog.events.BrowserEvent} event Event object.
- * @protected
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.handleTooltipMouseOver = function(event) {
- if (this.getActiveElement() != this.getElement()) {
- this.tracking_ = false;
- this.setActiveElement(this.getElement());
- }
- };
- /**
- * Override hide delay with cursor tracking hide delay while tracking.
- * @return {number} Hide delay to use.
- * @override
- */
- goog.ui.AdvancedTooltip.prototype.getHideDelayMs = function() {
- return this.tracking_ ? this.cursorTrackingHideDelayMs_ :
- goog.ui.AdvancedTooltip.base(this, 'getHideDelayMs');
- };
- /**
- * Forces the recalculation of the hotspot on the next mouse over event.
- * @deprecated Not ever necessary to call this function. Hot spot is calculated
- * as necessary.
- */
- goog.ui.AdvancedTooltip.prototype.resetHotSpot = goog.nullFunction;
|