2 'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n></div>\n"}});
3 define("dijit/Tooltip", [
4 "dojo/_base/array", // array.forEach array.indexOf array.map
5 "dojo/_base/declare", // declare
6 "dojo/_base/fx", // fx.fadeIn fx.fadeOut
7 "dojo/dom", // dom.byId
8 "dojo/dom-class", // domClass.add
9 "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position
10 "dojo/dom-style", // domStyle.set, domStyle.get
11 "dojo/_base/lang", // lang.hitch lang.isArrayLike
12 "dojo/_base/sniff", // has("ie")
13 "dojo/_base/window", // win.body
14 "./_base/manager", // manager.defaultDuration
19 "dojo/text!./templates/Tooltip.html",
20 "." // sets dijit.showTooltip etc. for back-compat
21 ], function(array
, declare
, fx
, dom
, domClass
, domGeometry
, domStyle
, lang
, has
, win
,
22 manager
, place
, _Widget
, _TemplatedMixin
, BackgroundIframe
, template
, dijit
){
25 var _Widget = dijit._Widget;
26 var BackgroundIframe = dijit.BackgroundIframe;
27 var _TemplatedMixin = dijit._TemplatedMixin;
33 // Defines dijit.Tooltip widget (to display a tooltip), showTooltip()/hideTooltip(), and _MasterTooltip
36 var MasterTooltip
= declare("dijit._MasterTooltip", [_Widget
, _TemplatedMixin
], {
38 // Internal widget that holds the actual tooltip markup,
39 // which occurs once per page.
40 // Called by Tooltip widgets which are just containers to hold
46 // Milliseconds to fade in/fade out
47 duration
: manager
.defaultDuration
,
49 templateString
: template
,
51 postCreate: function(){
52 win
.body().appendChild(this.domNode
);
54 this.bgIframe
= new BackgroundIframe(this.domNode
);
56 // Setup fade-in and fade-out functions.
57 this.fadeIn
= fx
.fadeIn({ node
: this.domNode
, duration
: this.duration
, onEnd
: lang
.hitch(this, "_onShow") });
58 this.fadeOut
= fx
.fadeOut({ node
: this.domNode
, duration
: this.duration
, onEnd
: lang
.hitch(this, "_onHide") });
61 show: function(innerHTML
, aroundNode
, position
, rtl
, textDir
){
63 // Display tooltip w/specified contents to right of specified node
64 // (To left if there's no space on the right, or if rtl == true)
66 // Contents of the tooltip
67 // aroundNode: DomNode || dijit.__Rectangle
68 // Specifies that tooltip should be next to this node / area
69 // position: String[]?
70 // List of positions to try to position tooltip (ex: ["right", "above"])
72 // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
73 // means "rtl"; specifies GUI direction, not text direction.
75 // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
78 if(this.aroundNode
&& this.aroundNode
=== aroundNode
&& this.containerNode
.innerHTML
== innerHTML
){
82 // reset width; it may have been set by orient() on a previous tooltip show()
83 this.domNode
.width
= "auto";
85 if(this.fadeOut
.status() == "playing"){
86 // previous tooltip is being hidden; wait until the hide completes then show new one
87 this._onDeck
=arguments
;
90 this.containerNode
.innerHTML
=innerHTML
;
92 this.set("textDir", textDir
);
93 this.containerNode
.align
= rtl
? "right" : "left"; //fix the text alignment
95 var pos
= place
.around(this.domNode
, aroundNode
,
96 position
&& position
.length
? position
: Tooltip
.defaultPosition
, !rtl
, lang
.hitch(this, "orient"));
98 // Position the tooltip connector for middle alignment.
99 // This could not have been done in orient() since the tooltip wasn't positioned at that time.
100 var aroundNodeCoords
= pos
.aroundNodePos
;
101 if(pos
.corner
.charAt(0) == 'M' && pos
.aroundCorner
.charAt(0) == 'M'){
102 this.connectorNode
.style
.top
= aroundNodeCoords
.y
+ ((aroundNodeCoords
.h
- this.connectorNode
.offsetHeight
) >> 1) - pos
.y
+ "px";
103 this.connectorNode
.style
.left
= "";
104 }else if(pos
.corner
.charAt(1) == 'M' && pos
.aroundCorner
.charAt(1) == 'M'){
105 this.connectorNode
.style
.left
= aroundNodeCoords
.x
+ ((aroundNodeCoords
.w
- this.connectorNode
.offsetWidth
) >> 1) - pos
.x
+ "px";
109 domStyle
.set(this.domNode
, "opacity", 0);
111 this.isShowingNow
= true;
112 this.aroundNode
= aroundNode
;
115 orient: function(/*DomNode*/ node
, /*String*/ aroundCorner
, /*String*/ tooltipCorner
, /*Object*/ spaceAvailable
, /*Object*/ aroundNodeCoords
){
117 // Private function to set CSS for tooltip node based on which position it's in.
118 // This is called by the dijit popup code. It will also reduce the tooltip's
119 // width to whatever width is available
122 this.connectorNode
.style
.top
= ""; //reset to default
124 //Adjust the spaceAvailable width, without changing the spaceAvailable object
125 var tooltipSpaceAvaliableWidth
= spaceAvailable
.w
- this.connectorNode
.offsetWidth
;
127 node
.className
= "dijitTooltip " +
129 "MR-ML": "dijitTooltipRight",
130 "ML-MR": "dijitTooltipLeft",
131 "TM-BM": "dijitTooltipAbove",
132 "BM-TM": "dijitTooltipBelow",
133 "BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
134 "TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
135 "BR-TR": "dijitTooltipBelow dijitTooltipABRight",
136 "TR-BR": "dijitTooltipAbove dijitTooltipABRight",
137 "BR-BL": "dijitTooltipRight",
138 "BL-BR": "dijitTooltipLeft"
139 }[aroundCorner
+ "-" + tooltipCorner
];
141 // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
142 this.domNode
.style
.width
= "auto";
143 var size
= domGeometry
.getContentBox(this.domNode
);
145 var width
= Math
.min((Math
.max(tooltipSpaceAvaliableWidth
,1)), size
.w
);
146 var widthWasReduced
= width
< size
.w
;
148 this.domNode
.style
.width
= width
+"px";
150 //Adjust width for tooltips that have a really long word or a nowrap setting
152 this.containerNode
.style
.overflow
= "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content
153 var scrollWidth
= this.containerNode
.scrollWidth
;
154 this.containerNode
.style
.overflow
= "visible"; //change it back
155 if(scrollWidth
> width
){
156 scrollWidth
= scrollWidth
+ domStyle
.get(this.domNode
,"paddingLeft") + domStyle
.get(this.domNode
,"paddingRight");
157 this.domNode
.style
.width
= scrollWidth
+ "px";
161 // Reposition the tooltip connector.
162 if(tooltipCorner
.charAt(0) == 'B' && aroundCorner
.charAt(0) == 'B'){
163 var mb
= domGeometry
.getMarginBox(node
);
164 var tooltipConnectorHeight
= this.connectorNode
.offsetHeight
;
165 if(mb
.h
> spaceAvailable
.h
){
166 // The tooltip starts at the top of the page and will extend past the aroundNode
167 var aroundNodePlacement
= spaceAvailable
.h
- ((aroundNodeCoords
.h
+ tooltipConnectorHeight
) >> 1);
168 this.connectorNode
.style
.top
= aroundNodePlacement
+ "px";
169 this.connectorNode
.style
.bottom
= "";
171 // Align center of connector with center of aroundNode, except don't let bottom
172 // of connector extend below bottom of tooltip content, or top of connector
173 // extend past top of tooltip content
174 this.connectorNode
.style
.bottom
= Math
.min(
175 Math
.max(aroundNodeCoords
.h
/2 - tooltipConnectorHeight/2, 0),
176 mb
.h
- tooltipConnectorHeight
) + "px";
177 this.connectorNode
.style
.top
= "";
180 // reset the tooltip back to the defaults
181 this.connectorNode
.style
.top
= "";
182 this.connectorNode
.style
.bottom
= "";
185 return Math
.max(0, size
.w
- tooltipSpaceAvaliableWidth
);
190 // Called at end of fade-in operation
194 // the arrow won't show up on a node w/an opacity filter
195 this.domNode
.style
.filter
="";
199 hide: function(aroundNode
){
203 if(this._onDeck
&& this._onDeck
[1] == aroundNode
){
204 // this hide request is for a show() that hasn't even started yet;
205 // just cancel the pending show()
207 }else if(this.aroundNode
=== aroundNode
){
208 // this hide request is for the currently displayed tooltip
210 this.isShowingNow
= false;
211 this.aroundNode
= null;
214 // just ignore the call, it's for a tooltip that has already been erased
220 // Called at end of fade-out operation
224 this.domNode
.style
.cssText
=""; // to position offscreen again
225 this.containerNode
.innerHTML
="";
227 // a show request has been queued up; do it now
228 this.show
.apply(this, this._onDeck
);
233 _setAutoTextDir: function(/*Object*/node
){
235 // Resolve "auto" text direction for children nodes
239 this.applyTextDir(node
, has("ie") ? node
.outerText
: node
.textContent
);
240 array
.forEach(node
.children
, function(child
){this._setAutoTextDir(child
); }, this);
243 _setTextDirAttr: function(/*String*/ textDir
){
245 // Setter for textDir.
247 // Users shouldn't call this function; they should be calling
248 // set('textDir', value)
252 this._set("textDir", typeof textDir
!= 'undefined'? textDir
: "");
253 if (textDir
== "auto"){
254 this._setAutoTextDir(this.containerNode
);
256 this.containerNode
.dir
= this.textDir
;
261 dijit
.showTooltip = function(innerHTML
, aroundNode
, position
, rtl
, textDir
){
263 // Static method to display tooltip w/specified contents in specified position.
264 // See description of dijit.Tooltip.defaultPosition for details on position parameter.
265 // If position is not specified then dijit.Tooltip.defaultPosition is used.
267 // Contents of the tooltip
268 // aroundNode: dijit.__Rectangle
269 // Specifies that tooltip should be next to this node / area
270 // position: String[]?
271 // List of positions to try to position tooltip (ex: ["right", "above"])
273 // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
274 // means "rtl"; specifies GUI direction, not text direction.
276 // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
278 // after/before don't work, but they used to, so for back-compat convert them to after-centered, before-centered
280 position
= array
.map(position
, function(val
){
281 return {after
: "after-centered", before
: "before-centered"}[val
] || val
;
285 if(!Tooltip
._masterTT
){ dijit
._masterTT
= Tooltip
._masterTT
= new MasterTooltip(); }
286 return Tooltip
._masterTT
.show(innerHTML
, aroundNode
, position
, rtl
, textDir
);
289 dijit
.hideTooltip = function(aroundNode
){
291 // Static method to hide the tooltip displayed via showTooltip()
292 return Tooltip
._masterTT
&& Tooltip
._masterTT
.hide(aroundNode
);
295 var Tooltip
= declare("dijit.Tooltip", _Widget
, {
297 // Pops up a tooltip (a help message) when you hover over a node.
300 // Text to display in the tooltip.
301 // Specified as innerHTML when creating the widget from markup.
304 // showDelay: Integer
305 // Number of milliseconds to wait after hovering over/focusing on the object, before
306 // the tooltip is displayed.
309 // connectId: String|String[]
310 // Id of domNode(s) to attach the tooltip to.
311 // When user hovers over specified dom node, the tooltip will appear.
314 // position: String[]
315 // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
318 _setConnectIdAttr: function(/*String|String[]*/ newId
){
320 // Connect to specified node(s)
322 // Remove connections to old nodes (if there are any)
323 array
.forEach(this._connections
|| [], function(nested
){
324 array
.forEach(nested
, lang
.hitch(this, "disconnect"));
327 // Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup()
328 this._connectIds
= array
.filter(lang
.isArrayLike(newId
) ? newId
: (newId
? [newId
] : []),
329 function(id
){ return dom
.byId(id
); });
332 this._connections
= array
.map(this._connectIds
, function(id
){
333 var node
= dom
.byId(id
);
335 this.connect(node
, "onmouseenter", "_onHover"),
336 this.connect(node
, "onmouseleave", "_onUnHover"),
337 this.connect(node
, "onfocus", "_onHover"),
338 this.connect(node
, "onblur", "_onUnHover")
342 this._set("connectId", newId
);
345 addTarget: function(/*DOMNODE || String*/ node
){
347 // Attach tooltip to specified node if it's not already connected
349 // TODO: remove in 2.0 and just use set("connectId", ...) interface
351 var id
= node
.id
|| node
;
352 if(array
.indexOf(this._connectIds
, id
) == -1){
353 this.set("connectId", this._connectIds
.concat(id
));
357 removeTarget: function(/*DomNode || String*/ node
){
359 // Detach tooltip from specified node
361 // TODO: remove in 2.0 and just use set("connectId", ...) interface
363 var id
= node
.id
|| node
, // map from DOMNode back to plain id string
364 idx
= array
.indexOf(this._connectIds
, id
);
366 // remove id (modifies original this._connectIds but that's OK in this case)
367 this._connectIds
.splice(idx
, 1);
368 this.set("connectId", this._connectIds
);
372 buildRendering: function(){
373 this.inherited(arguments
);
374 domClass
.add(this.domNode
,"dijitTooltipData");
378 this.inherited(arguments
);
380 // If this tooltip was created in a template, or for some other reason the specified connectId[s]
381 // didn't exist during the widget's initialization, then connect now.
382 var ids
= this.connectId
;
383 array
.forEach(lang
.isArrayLike(ids
) ? ids
: [ids
], this.addTarget
, this);
386 _onHover: function(/*Event*/ e
){
388 // Despite the name of this method, it actually handles both hover and focus
389 // events on the target node, setting a timer to show the tooltip.
392 if(!this._showTimer
){
393 var target
= e
.target
;
394 this._showTimer
= setTimeout(lang
.hitch(this, function(){this.open(target
)}), this.showDelay
);
398 _onUnHover: function(/*Event*/ /*===== e =====*/){
400 // Despite the name of this method, it actually handles both mouseleave and blur
401 // events on the target node, hiding the tooltip.
405 // keep a tooltip open if the associated element still has focus (even though the
407 if(this._focus
){ return; }
410 clearTimeout(this._showTimer
);
411 delete this._showTimer
;
416 open: function(/*DomNode*/ target
){
418 // Display the tooltip; usually not called directly.
423 clearTimeout(this._showTimer
);
424 delete this._showTimer
;
426 Tooltip
.show(this.label
|| this.domNode
.innerHTML
, target
, this.position
, !this.isLeftToRight(), this.textDir
);
428 this._connectNode
= target
;
429 this.onShow(target
, this.position
);
434 // Hide the tooltip or cancel timer for show of tooltip
438 if(this._connectNode
){
439 // if tooltip is currently shown
440 Tooltip
.hide(this._connectNode
);
441 delete this._connectNode
;
445 // if tooltip is scheduled to be shown (after a brief delay)
446 clearTimeout(this._showTimer
);
447 delete this._showTimer
;
451 onShow: function(/*===== target, position =====*/){
453 // Called when the tooltip is shown
460 // Called when the tooltip is hidden
465 uninitialize: function(){
467 this.inherited(arguments
);
471 Tooltip
._MasterTooltip
= MasterTooltip
; // for monkey patching
472 Tooltip
.show
= dijit
.showTooltip
; // export function through module return value
473 Tooltip
.hide
= dijit
.hideTooltip
; // export function through module return value
475 // dijit.Tooltip.defaultPosition: String[]
476 // This variable controls the position of tooltips, if the position is not specified to
477 // the Tooltip widget or *TextBox widget itself. It's an array of strings with the values
478 // possible for `dijit/place::around()`. The recommended values are:
480 // * before-centered: centers tooltip to the left of the anchor node/widget, or to the right
481 // in the case of RTL scripts like Hebrew and Arabic
482 // * after-centered: centers tooltip to the right of the anchor node/widget, or to the left
483 // in the case of RTL scripts like Hebrew and Arabic
484 // * above-centered: tooltip is centered above anchor node
485 // * below-centered: tooltip is centered above anchor node
487 // The list is positions is tried, in order, until a position is found where the tooltip fits
488 // within the viewport.
490 // Be careful setting this parameter. A value of "above-centered" may work fine until the user scrolls
491 // the screen so that there's no room above the target node. Nodes with drop downs, like
492 // DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
493 // that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
494 // is only room below (or above) the target node, but not both.
495 Tooltip
.defaultPosition
= ["after-centered", "before-centered"];