You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
11 KiB
JavaScript
361 lines
11 KiB
JavaScript
![]()
15 years ago
|
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,
|
||
|
|
||
|
templatePath: dojo.moduleUrl("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){
|
||
|
// summary:
|
||
|
// Display tooltip w/specified contents to right of specified node
|
||
|
// (To left if there's no space on the right, or if LTR==right)
|
||
|
|
||
|
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;
|
||
|
|
||
|
// Firefox bug. when innerHTML changes to be shorter than previous
|
||
|
// one, the node size will not be updated until it moves.
|
||
|
this.domNode.style.top = (this.domNode.offsetTop + 1) + "px";
|
||
|
|
||
|
// position the element and change CSS according to position[] (a list of positions to try)
|
||
|
var align = {};
|
||
|
var ltr = this.isLeftToRight();
|
||
|
dojo.forEach( (position && position.length) ? position : dijit.Tooltip.defaultPosition, function(pos){
|
||
|
switch(pos){
|
||
|
case "after":
|
||
|
align[ltr ? "BR" : "BL"] = ltr ? "BL" : "BR";
|
||
|
break;
|
||
|
case "before":
|
||
|
align[ltr ? "BL" : "BR"] = ltr ? "BR" : "BL";
|
||
|
break;
|
||
|
case "below":
|
||
|
// first try to align left borders, next try to align right borders (or reverse for RTL mode)
|
||
|
align[ltr ? "BL" : "BR"] = ltr ? "TL" : "TR";
|
||
|
align[ltr ? "BR" : "BL"] = ltr ? "TR" : "TL";
|
||
|
break;
|
||
|
case "above":
|
||
|
default:
|
||
|
// first try to align left borders, next try to align right borders (or reverse for RTL mode)
|
||
|
align[ltr ? "TL" : "TR"] = ltr ? "BL" : "BR";
|
||
|
align[ltr ? "TR" : "TL"] = ltr ? "BR" : "BL";
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, align, 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
|
||
|
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){
|
||
|
// 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);
|
||
|
};
|
||
|
|
||
|
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: [],
|
||
|
|
||
|
_setConnectIdAttr: function(ids){
|
||
|
// TODO: erase old conections
|
||
|
|
||
|
this._connectNodes = [];
|
||
|
|
||
|
// TODO: rename connectId to connectIds for 2.0, and remove this code converting from string to array
|
||
|
this.connectId = dojo.isArrayLike(ids) ? ids : [ids];
|
||
|
|
||
|
dojo.forEach(this.connectId, function(id) {
|
||
|
var node = dojo.byId(id);
|
||
|
if (node) {
|
||
|
this._connectNodes.push(node);
|
||
|
dojo.forEach(["onMouseEnter", "onMouseLeave", "onFocus", "onBlur"], function(event){
|
||
|
this.connect(node, event.toLowerCase(), "_"+event);
|
||
|
}, this);
|
||
|
if(dojo.isIE){
|
||
|
// BiDi workaround
|
||
|
node.style.zoom = 1;
|
||
|
}
|
||
|
}
|
||
|
}, this);
|
||
|
},
|
||
|
|
||
|
postCreate: function(){
|
||
|
dojo.addClass(this.domNode,"dijitTooltipData");
|
||
|
},
|
||
|
|
||
|
_onMouseEnter: function(/*Event*/ e){
|
||
|
// summary:
|
||
|
// Handler for mouseenter event on the target node
|
||
|
// tags:
|
||
|
// private
|
||
|
this._onHover(e);
|
||
|
},
|
||
|
|
||
|
_onMouseLeave: function(/*Event*/ e){
|
||
|
// summary:
|
||
|
// Handler for mouseleave event on the target node
|
||
|
// tags:
|
||
|
// private
|
||
|
this._onUnHover(e);
|
||
|
},
|
||
|
|
||
|
_onFocus: function(/*Event*/ e){
|
||
|
// summary:
|
||
|
// Handler for focus event on the target node
|
||
|
// tags:
|
||
|
// private
|
||
|
|
||
|
// TODO: this is dangerously named, as the dijit focus manager calls
|
||
|
// _onFocus() on any widget that gets focus (whereas in this class we
|
||
|
// are connecting onfocus on the *target* DOM node to this method
|
||
|
|
||
|
this._focus = true;
|
||
|
this._onHover(e);
|
||
|
this.inherited(arguments);
|
||
|
},
|
||
|
|
||
|
_onBlur: function(/*Event*/ e){
|
||
|
// summary:
|
||
|
// Handler for blur event on the target node
|
||
|
// tags:
|
||
|
// private
|
||
|
|
||
|
// TODO: rename; see above comment
|
||
|
|
||
|
this._focus = false;
|
||
|
this._onUnHover(e);
|
||
|
this.inherited(arguments);
|
||
|
},
|
||
|
|
||
|
_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();
|
||
|
},
|
||
|
|
||
|
open: function(/*DomNode*/ target){
|
||
|
// summary:
|
||
|
// Display the tooltip; usually not called directly.
|
||
|
// tags:
|
||
|
// private
|
||
|
|
||
|
target = target || this._connectNodes[0];
|
||
|
if(!target){ return; }
|
||
|
|
||
|
if(this._showTimer){
|
||
|
clearTimeout(this._showTimer);
|
||
|
delete this._showTimer;
|
||
|
}
|
||
|
dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position);
|
||
|
|
||
|
this._connectNode = target;
|
||
|
},
|
||
|
|
||
|
close: function(){
|
||
|
// summary:
|
||
|
// Hide the tooltip or cancel timer for show of tooltip
|
||
|
// tags:
|
||
|
// private
|
||
|
|
||
|
if(this._connectNode){
|
||
|
// if tooltip is currently shown
|
||
|
dijit.hideTooltip(this._connectNode);
|
||
|
delete this._connectNode;
|
||
|
}
|
||
|
if(this._showTimer){
|
||
|
// if tooltip is scheduled to be shown (after a brief delay)
|
||
|
clearTimeout(this._showTimer);
|
||
|
delete this._showTimer;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
uninitialize: function(){
|
||
|
this.close();
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
// dijit.Tooltip.defaultPosition: String[]
|
||
|
// This variable controls the position of tooltips, if the position is not specified to
|
||
|
// the Tooltip widget or *TextBox widget itself. It's an array of strings with the following values:
|
||
|
//
|
||
|
// * before: places tooltip to the left of the target node/widget, or to the right in
|
||
|
// the case of RTL scripts like Hebrew and Arabic
|
||
|
// * after: places tooltip to the right of the target node/widget, or to the left in
|
||
|
// the case of RTL scripts like Hebrew and Arabic
|
||
|
// * above: tooltip goes above target node
|
||
|
// * below: tooltip goes below target node
|
||
|
//
|
||
|
// The list is positions is tried, in order, until a position is found where the tooltip fits
|
||
|
// within the viewport.
|
||
|
//
|
||
|
// Be careful setting this parameter. A value of "above" may work fine until the user scrolls
|
||
|
// the screen so that there's no room above the target node. Nodes with drop downs, like
|
||
|
// DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
|
||
|
// that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
|
||
|
// is only room below (or above) the target node, but not both.
|
||
|
dijit.Tooltip.defaultPosition = ["after", "before"];
|