]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/Tooltip.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dijit / Tooltip.js.uncompressed.js
1 require({cache:{
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
15 "./place",
16 "./_Widget",
17 "./_TemplatedMixin",
18 "./BackgroundIframe",
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){
23
24 /*=====
25 var _Widget = dijit._Widget;
26 var BackgroundIframe = dijit.BackgroundIframe;
27 var _TemplatedMixin = dijit._TemplatedMixin;
28 =====*/
29
30 // module:
31 // dijit/Tooltip
32 // summary:
33 // Defines dijit.Tooltip widget (to display a tooltip), showTooltip()/hideTooltip(), and _MasterTooltip
34
35
36 var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], {
37 // summary:
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
41 // the markup
42 // tags:
43 // protected
44
45 // duration: Integer
46 // Milliseconds to fade in/fade out
47 duration: manager.defaultDuration,
48
49 templateString: template,
50
51 postCreate: function(){
52 win.body().appendChild(this.domNode);
53
54 this.bgIframe = new BackgroundIframe(this.domNode);
55
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") });
59 },
60
61 show: function(innerHTML, aroundNode, position, rtl, textDir){
62 // summary:
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)
65 // innerHTML: String
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"])
71 // rtl: Boolean?
72 // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
73 // means "rtl"; specifies GUI direction, not text direction.
74 // textDir: String?
75 // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
76
77
78 if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){
79 return;
80 }
81
82 // reset width; it may have been set by orient() on a previous tooltip show()
83 this.domNode.width = "auto";
84
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;
88 return;
89 }
90 this.containerNode.innerHTML=innerHTML;
91
92 this.set("textDir", textDir);
93 this.containerNode.align = rtl? "right" : "left"; //fix the text alignment
94
95 var pos = place.around(this.domNode, aroundNode,
96 position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient"));
97
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";
106 }
107
108 // show it
109 domStyle.set(this.domNode, "opacity", 0);
110 this.fadeIn.play();
111 this.isShowingNow = true;
112 this.aroundNode = aroundNode;
113 },
114
115 orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
116 // summary:
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
120 // tags:
121 // protected
122 this.connectorNode.style.top = ""; //reset to default
123
124 //Adjust the spaceAvailable width, without changing the spaceAvailable object
125 var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth;
126
127 node.className = "dijitTooltip " +
128 {
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];
140
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);
144
145 var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w);
146 var widthWasReduced = width < size.w;
147
148 this.domNode.style.width = width+"px";
149
150 //Adjust width for tooltips that have a really long word or a nowrap setting
151 if(widthWasReduced){
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";
158 }
159 }
160
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 = "";
170 }else{
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 = "";
178 }
179 }else{
180 // reset the tooltip back to the defaults
181 this.connectorNode.style.top = "";
182 this.connectorNode.style.bottom = "";
183 }
184
185 return Math.max(0, size.w - tooltipSpaceAvaliableWidth);
186 },
187
188 _onShow: function(){
189 // summary:
190 // Called at end of fade-in operation
191 // tags:
192 // protected
193 if(has("ie")){
194 // the arrow won't show up on a node w/an opacity filter
195 this.domNode.style.filter="";
196 }
197 },
198
199 hide: function(aroundNode){
200 // summary:
201 // Hide the tooltip
202
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()
206 this._onDeck=null;
207 }else if(this.aroundNode === aroundNode){
208 // this hide request is for the currently displayed tooltip
209 this.fadeIn.stop();
210 this.isShowingNow = false;
211 this.aroundNode = null;
212 this.fadeOut.play();
213 }else{
214 // just ignore the call, it's for a tooltip that has already been erased
215 }
216 },
217
218 _onHide: function(){
219 // summary:
220 // Called at end of fade-out operation
221 // tags:
222 // protected
223
224 this.domNode.style.cssText=""; // to position offscreen again
225 this.containerNode.innerHTML="";
226 if(this._onDeck){
227 // a show request has been queued up; do it now
228 this.show.apply(this, this._onDeck);
229 this._onDeck=null;
230 }
231 },
232
233 _setAutoTextDir: function(/*Object*/node){
234 // summary:
235 // Resolve "auto" text direction for children nodes
236 // tags:
237 // private
238
239 this.applyTextDir(node, has("ie") ? node.outerText : node.textContent);
240 array.forEach(node.children, function(child){this._setAutoTextDir(child); }, this);
241 },
242
243 _setTextDirAttr: function(/*String*/ textDir){
244 // summary:
245 // Setter for textDir.
246 // description:
247 // Users shouldn't call this function; they should be calling
248 // set('textDir', value)
249 // tags:
250 // private
251
252 this._set("textDir", typeof textDir != 'undefined'? textDir : "");
253 if (textDir == "auto"){
254 this._setAutoTextDir(this.containerNode);
255 }else{
256 this.containerNode.dir = this.textDir;
257 }
258 }
259 });
260
261 dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir){
262 // summary:
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.
266 // innerHTML: String
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"])
272 // rtl: Boolean?
273 // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
274 // means "rtl"; specifies GUI direction, not text direction.
275 // textDir: String?
276 // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
277
278 // after/before don't work, but they used to, so for back-compat convert them to after-centered, before-centered
279 if(position){
280 position = array.map(position, function(val){
281 return {after: "after-centered", before: "before-centered"}[val] || val;
282 });
283 }
284
285 if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); }
286 return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir);
287 };
288
289 dijit.hideTooltip = function(aroundNode){
290 // summary:
291 // Static method to hide the tooltip displayed via showTooltip()
292 return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode);
293 };
294
295 var Tooltip = declare("dijit.Tooltip", _Widget, {
296 // summary:
297 // Pops up a tooltip (a help message) when you hover over a node.
298
299 // label: String
300 // Text to display in the tooltip.
301 // Specified as innerHTML when creating the widget from markup.
302 label: "",
303
304 // showDelay: Integer
305 // Number of milliseconds to wait after hovering over/focusing on the object, before
306 // the tooltip is displayed.
307 showDelay: 400,
308
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.
312 connectId: [],
313
314 // position: String[]
315 // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
316 position: [],
317
318 _setConnectIdAttr: function(/*String|String[]*/ newId){
319 // summary:
320 // Connect to specified node(s)
321
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"));
325 }, this);
326
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); });
330
331 // Make connections
332 this._connections = array.map(this._connectIds, function(id){
333 var node = dom.byId(id);
334 return [
335 this.connect(node, "onmouseenter", "_onHover"),
336 this.connect(node, "onmouseleave", "_onUnHover"),
337 this.connect(node, "onfocus", "_onHover"),
338 this.connect(node, "onblur", "_onUnHover")
339 ];
340 }, this);
341
342 this._set("connectId", newId);
343 },
344
345 addTarget: function(/*DOMNODE || String*/ node){
346 // summary:
347 // Attach tooltip to specified node if it's not already connected
348
349 // TODO: remove in 2.0 and just use set("connectId", ...) interface
350
351 var id = node.id || node;
352 if(array.indexOf(this._connectIds, id) == -1){
353 this.set("connectId", this._connectIds.concat(id));
354 }
355 },
356
357 removeTarget: function(/*DomNode || String*/ node){
358 // summary:
359 // Detach tooltip from specified node
360
361 // TODO: remove in 2.0 and just use set("connectId", ...) interface
362
363 var id = node.id || node, // map from DOMNode back to plain id string
364 idx = array.indexOf(this._connectIds, id);
365 if(idx >= 0){
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);
369 }
370 },
371
372 buildRendering: function(){
373 this.inherited(arguments);
374 domClass.add(this.domNode,"dijitTooltipData");
375 },
376
377 startup: function(){
378 this.inherited(arguments);
379
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);
384 },
385
386 _onHover: function(/*Event*/ e){
387 // summary:
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.
390 // tags:
391 // private
392 if(!this._showTimer){
393 var target = e.target;
394 this._showTimer = setTimeout(lang.hitch(this, function(){this.open(target)}), this.showDelay);
395 }
396 },
397
398 _onUnHover: function(/*Event*/ /*===== e =====*/){
399 // summary:
400 // Despite the name of this method, it actually handles both mouseleave and blur
401 // events on the target node, hiding the tooltip.
402 // tags:
403 // private
404
405 // keep a tooltip open if the associated element still has focus (even though the
406 // mouse moved away)
407 if(this._focus){ return; }
408
409 if(this._showTimer){
410 clearTimeout(this._showTimer);
411 delete this._showTimer;
412 }
413 this.close();
414 },
415
416 open: function(/*DomNode*/ target){
417 // summary:
418 // Display the tooltip; usually not called directly.
419 // tags:
420 // private
421
422 if(this._showTimer){
423 clearTimeout(this._showTimer);
424 delete this._showTimer;
425 }
426 Tooltip.show(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight(), this.textDir);
427
428 this._connectNode = target;
429 this.onShow(target, this.position);
430 },
431
432 close: function(){
433 // summary:
434 // Hide the tooltip or cancel timer for show of tooltip
435 // tags:
436 // private
437
438 if(this._connectNode){
439 // if tooltip is currently shown
440 Tooltip.hide(this._connectNode);
441 delete this._connectNode;
442 this.onHide();
443 }
444 if(this._showTimer){
445 // if tooltip is scheduled to be shown (after a brief delay)
446 clearTimeout(this._showTimer);
447 delete this._showTimer;
448 }
449 },
450
451 onShow: function(/*===== target, position =====*/){
452 // summary:
453 // Called when the tooltip is shown
454 // tags:
455 // callback
456 },
457
458 onHide: function(){
459 // summary:
460 // Called when the tooltip is hidden
461 // tags:
462 // callback
463 },
464
465 uninitialize: function(){
466 this.close();
467 this.inherited(arguments);
468 }
469 });
470
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
474
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:
479 //
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
486 //
487 // The list is positions is tried, in order, until a position is found where the tooltip fits
488 // within the viewport.
489 //
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"];
496
497
498 return Tooltip;
499 });