source: [view]
dojo.provide("dijit.Tooltip");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare(
"dijit._MasterTooltip",
[dijit._Widget, dijit._Templated],
{
// summary:
// Internal widget that holds the actual tooltip markup,
// which occurs once per page.
// Called by Tooltip widgets which are just containers to hold
// the markup
// tags:
// protected
// duration: Integer
// Milliseconds to fade in/fade out
duration: dijit.defaultDuration,
templateString: dojo.cache("dijit", "templates/Tooltip.html"),
postCreate: function(){
dojo.body().appendChild(this.domNode);
this.bgIframe = new dijit.BackgroundIframe(this.domNode);
// Setup fade-in and fade-out functions.
this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });
},
show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
// summary:
// Display tooltip w/specified contents to right of specified node
// (To left if there's no space on the right, or if rtl == true)
if(this.aroundNode && this.aroundNode === aroundNode){
return;
}
if(this.fadeOut.status() == "playing"){
// previous tooltip is being hidden; wait until the hide completes then show new one
this._onDeck=arguments;
return;
}
this.containerNode.innerHTML=innerHTML;
var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, dijit.getPopupAroundAlignment((position && position.length) ? position : dijit.Tooltip.defaultPosition, !rtl), dojo.hitch(this, "orient"));
// show it
dojo.style(this.domNode, "opacity", 0);
this.fadeIn.play();
this.isShowingNow = true;
this.aroundNode = aroundNode;
},
orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){
// summary:
// Private function to set CSS for tooltip node based on which position it's in.
// This is called by the dijit popup code.
// tags:
// protected
node.className = "dijitTooltip " +
{
"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
"BR-BL": "dijitTooltipRight",
"BL-BR": "dijitTooltipLeft"
}[aroundCorner + "-" + tooltipCorner];
},
_onShow: function(){
// summary:
// Called at end of fade-in operation
// tags:
// protected
if(dojo.isIE){
// the arrow won't show up on a node w/an opacity filter
this.domNode.style.filter="";
}
},
hide: function(aroundNode){
// summary:
// Hide the tooltip
if(this._onDeck && this._onDeck[1] == aroundNode){
// this hide request is for a show() that hasn't even started yet;
// just cancel the pending show()
this._onDeck=null;
}else if(this.aroundNode === aroundNode){
// this hide request is for the currently displayed tooltip
this.fadeIn.stop();
this.isShowingNow = false;
this.aroundNode = null;
this.fadeOut.play();
}else{
// just ignore the call, it's for a tooltip that has already been erased
}
},
_onHide: function(){
// summary:
// Called at end of fade-out operation
// tags:
// protected
this.domNode.style.cssText=""; // to position offscreen again
this.containerNode.innerHTML="";
if(this._onDeck){
// a show request has been queued up; do it now
this.show.apply(this, this._onDeck);
this._onDeck=null;
}
}
}
);
dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
// summary:
// Display tooltip w/specified contents in specified position.
// See description of dijit.Tooltip.defaultPosition for details on position parameter.
// If position is not specified then dijit.Tooltip.defaultPosition is used.
if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
return dijit._masterTT.show(innerHTML, aroundNode, position, rtl);
};
dijit.hideTooltip = function(aroundNode){
// summary:
// Hide the tooltip
if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
return dijit._masterTT.hide(aroundNode);
};
dojo.declare(
"dijit.Tooltip",
dijit._Widget,
{
// summary:
// Pops up a tooltip (a help message) when you hover over a node.
// label: String
// Text to display in the tooltip.
// Specified as innerHTML when creating the widget from markup.
label: "",
// showDelay: Integer
// Number of milliseconds to wait after hovering over/focusing on the object, before
// the tooltip is displayed.
showDelay: 400,
// connectId: [const] String[]
// Id's of domNodes to attach the tooltip to.
// When user hovers over any of the specified dom nodes, the tooltip will appear.
//
// Note: Currently connectId can only be specified on initialization, it cannot
// be changed via attr('connectId', ...)
//
// Note: in 2.0 this will be renamed to connectIds for less confusion.
connectId: [],
// position: String[]
// See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
position: [],
constructor: function(){
// Map id's of nodes I'm connected to to a list of the this.connect() handles
this._nodeConnectionsById = {};
},
_setConnectIdAttr: function(newIds){
for(var oldId in this._nodeConnectionsById){
this.removeTarget(oldId);
}
dojo.forEach(dojo.isArrayLike(newIds) ? newIds : [newIds], this.addTarget, this);
},
_getConnectIdAttr: function(){
var ary = [];
for(var id in this._nodeConnectionsById){
ary.push(id);
}
return ary;
},
addTarget: function(/*DOMNODE || String*/ id){
// summary:
// Attach tooltip to specified node, if it's not already connected
var node = dojo.byId(id);
if(!node){ return; }
if(node.id in this._nodeConnectionsById){ return; }//Already connected
this._nodeConnectionsById[node.id] = [
this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
this.connect(node, "onfocus", "_onTargetFocus"),
this.connect(node, "onblur", "_onTargetBlur")
];
},
removeTarget: function(/*DOMNODE || String*/ node){
// summary:
// Detach tooltip from specified node
// map from DOMNode back to plain id string
var id = node.id || node;
if(id in this._nodeConnectionsById){
dojo.forEach(this._nodeConnectionsById[id], this.disconnect, this);
delete this._nodeConnectionsById[id];
}
},
postCreate: function(){
dojo.addClass(this.domNode,"dijitTooltipData");
},
startup: function(){
this.inherited(arguments);
// If this tooltip was created in a template, or for some other reason the specified connectId[s]
// didn't exist during the widget's initialization, then connect now.
var ids = this.connectId;
dojo.forEach(dojo.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
},
_onTargetMouseEnter: function(/*Event*/ e){
// summary:
// Handler for mouseenter event on the target node
// tags:
// private
this._onHover(e);
},
_onTargetMouseLeave: function(/*Event*/ e){
// summary:
// Handler for mouseleave event on the target node
// tags:
// private
this._onUnHover(e);
},
_onTargetFocus: function(/*Event*/ e){
// summary:
// Handler for focus event on the target node
// tags:
// private
this._focus = true;
this._onHover(e);
},
_onTargetBlur: function(/*Event*/ e){
// summary:
// Handler for blur event on the target node
// tags:
// private
this._focus = false;
this._onUnHover(e);
},
_onHover: function(/*Event*/ e){
// summary:
// Despite the name of this method, it actually handles both hover and focus
// events on the target node, setting a timer to show the tooltip.
// tags:
// private
if(!this._showTimer){
var target = e.target;
this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay);
}
},
_onUnHover: function(/*Event*/ e){
// summary:
// Despite the name of this method, it actually handles both mouseleave and blur
// events on the target node, hiding the tooltip.
// tags:
// private
// keep a tooltip open if the associated element still has focus (even though the
// mouse moved away)
if(this._focus){ return; }
if(this._showTimer){
clearTimeout(this._showTimer);
delete this._showTimer;
}
this.close();