diff options
author | Andrew Dolgov <[email protected]> | 2011-11-08 20:40:44 +0400 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2011-11-08 20:40:44 +0400 |
commit | 81bea17aefb26859f825b9293c7c99192874806e (patch) | |
tree | fb244408ca271affa2899adb634788802c9a89d8 /lib/dijit/Tooltip.js | |
parent | 870a70e109ac9e80a88047044530de53d0404ec7 (diff) |
upgrade Dojo to 1.6.1
Diffstat (limited to 'lib/dijit/Tooltip.js')
-rw-r--r-- | lib/dijit/Tooltip.js | 571 |
1 files changed, 428 insertions, 143 deletions
diff --git a/lib/dijit/Tooltip.js b/lib/dijit/Tooltip.js index fea9a0bc1..46b3a3805 100644 --- a/lib/dijit/Tooltip.js +++ b/lib/dijit/Tooltip.js @@ -1,155 +1,440 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit.Tooltip"]){ -dojo._hasResource["dijit.Tooltip"]=true; +if(!dojo._hasResource["dijit.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit.Tooltip"] = true; dojo.provide("dijit.Tooltip"); dojo.require("dijit._Widget"); dojo.require("dijit._Templated"); -dojo.declare("dijit._MasterTooltip",[dijit._Widget,dijit._Templated],{duration:dijit.defaultDuration,templateString:dojo.cache("dijit","templates/Tooltip.html","<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n"),postCreate:function(){ -dojo.body().appendChild(this.domNode); -this.bgIframe=new dijit.BackgroundIframe(this.domNode); -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(_1,_2,_3,_4){ -if(this.aroundNode&&this.aroundNode===_2){ -return; -} -if(this.fadeOut.status()=="playing"){ -this._onDeck=arguments; -return; -} -this.containerNode.innerHTML=_1; -var _5=dijit.placeOnScreenAroundElement(this.domNode,_2,dijit.getPopupAroundAlignment((_3&&_3.length)?_3:dijit.Tooltip.defaultPosition,!_4),dojo.hitch(this,"orient")); -dojo.style(this.domNode,"opacity",0); -this.fadeIn.play(); -this.isShowingNow=true; -this.aroundNode=_2; -},orient:function(_6,_7,_8){ -_6.className="dijitTooltip "+{"BL-TL":"dijitTooltipBelow dijitTooltipABLeft","TL-BL":"dijitTooltipAbove dijitTooltipABLeft","BR-TR":"dijitTooltipBelow dijitTooltipABRight","TR-BR":"dijitTooltipAbove dijitTooltipABRight","BR-BL":"dijitTooltipRight","BL-BR":"dijitTooltipLeft"}[_7+"-"+_8]; -},_onShow:function(){ -if(dojo.isIE){ -this.domNode.style.filter=""; -} -},hide:function(_9){ -if(this._onDeck&&this._onDeck[1]==_9){ -this._onDeck=null; -}else{ -if(this.aroundNode===_9){ -this.fadeIn.stop(); -this.isShowingNow=false; -this.aroundNode=null; -this.fadeOut.play(); -}else{ -} -} -},_onHide:function(){ -this.domNode.style.cssText=""; -this.containerNode.innerHTML=""; -if(this._onDeck){ -this.show.apply(this,this._onDeck); -this._onDeck=null; -} -}}); -dijit.showTooltip=function(_a,_b,_c,_d){ -if(!dijit._masterTT){ -dijit._masterTT=new dijit._MasterTooltip(); -} -return dijit._masterTT.show(_a,_b,_c,_d); + + +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", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" dojoAttachPoint=\"connectorNode\"></div\n></div>\n"), + + 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; + } + + // reset width; it may have been set by orient() on a previous tooltip show() + this.domNode.width = "auto"; + + 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, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){ + // summary: + // Private function to set CSS for tooltip node based on which position it's in. + // This is called by the dijit popup code. It will also reduce the tooltip's + // width to whatever width is available + // tags: + // protected + this.connectorNode.style.top = ""; //reset to default + + //Adjust the spaceAvailable width, without changing the spaceAvailable object + var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth; + + 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]; + + // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen + this.domNode.style.width = "auto"; + var size = dojo.contentBox(this.domNode); + + var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w); + var widthWasReduced = width < size.w; + + this.domNode.style.width = width+"px"; + + //Adjust width for tooltips that have a really long word or a nowrap setting + if(widthWasReduced){ + this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content + var scrollWidth = this.containerNode.scrollWidth; + this.containerNode.style.overflow = "visible"; //change it back + if(scrollWidth > width){ + scrollWidth = scrollWidth + dojo.style(this.domNode,"paddingLeft") + dojo.style(this.domNode,"paddingRight"); + this.domNode.style.width = scrollWidth + "px"; + } + } + + // Reposition the tooltip connector. + if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){ + var mb = dojo.marginBox(node); + var tooltipConnectorHeight = this.connectorNode.offsetHeight; + if(mb.h > spaceAvailable.h){ + // The tooltip starts at the top of the page and will extend past the aroundNode + var aroundNodePlacement = spaceAvailable.h - (aroundNodeCoords.h / 2) - (tooltipConnectorHeight / 2); + this.connectorNode.style.top = aroundNodePlacement + "px"; + this.connectorNode.style.bottom = ""; + }else{ + // Align center of connector with center of aroundNode, except don't let bottom + // of connector extend below bottom of tooltip content, or top of connector + // extend past top of tooltip content + this.connectorNode.style.bottom = Math.min( + Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0), + mb.h - tooltipConnectorHeight) + "px"; + this.connectorNode.style.top = ""; + } + }else{ + // reset the tooltip back to the defaults + this.connectorNode.style.top = ""; + this.connectorNode.style.bottom = ""; + } + + return Math.max(0, size.w - tooltipSpaceAvaliableWidth); + }, + + _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(_e){ -if(!dijit._masterTT){ -dijit._masterTT=new dijit._MasterTooltip(); -} -return dijit._masterTT.hide(_e); + +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,{label:"",showDelay:400,connectId:[],position:[],constructor:function(){ -this._nodeConnectionsById={}; -},_setConnectIdAttr:function(_f){ -for(var _10 in this._nodeConnectionsById){ -this.removeTarget(_10); -} -dojo.forEach(dojo.isArrayLike(_f)?_f:[_f],this.addTarget,this); -},_getConnectIdAttr:function(){ -var ary=[]; -for(var id in this._nodeConnectionsById){ -ary.push(id); -} -return ary; -},addTarget:function(id){ -var _11=dojo.byId(id); -if(!_11){ -return; -} -if(_11.id in this._nodeConnectionsById){ -return; -} -this._nodeConnectionsById[_11.id]=[this.connect(_11,"onmouseenter","_onTargetMouseEnter"),this.connect(_11,"onmouseleave","_onTargetMouseLeave"),this.connect(_11,"onfocus","_onTargetFocus"),this.connect(_11,"onblur","_onTargetBlur")]; -},removeTarget:function(_12){ -var id=_12.id||_12; -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); -var ids=this.connectId; -dojo.forEach(dojo.isArrayLike(ids)?ids:[ids],this.addTarget,this); -},_onTargetMouseEnter:function(e){ -this._onHover(e); -},_onTargetMouseLeave:function(e){ -this._onUnHover(e); -},_onTargetFocus:function(e){ -this._focus=true; -this._onHover(e); -},_onTargetBlur:function(e){ -this._focus=false; -this._onUnHover(e); -},_onHover:function(e){ -if(!this._showTimer){ -var _13=e.target; -this._showTimer=setTimeout(dojo.hitch(this,function(){ -this.open(_13); -}),this.showDelay); -} -},_onUnHover:function(e){ -if(this._focus){ -return; -} -if(this._showTimer){ -clearTimeout(this._showTimer); -delete this._showTimer; -} -this.close(); -},open:function(_14){ -if(this._showTimer){ -clearTimeout(this._showTimer); -delete this._showTimer; -} -dijit.showTooltip(this.label||this.domNode.innerHTML,_14,this.position,!this.isLeftToRight()); -this._connectNode=_14; -this.onShow(_14,this.position); -},close:function(){ -if(this._connectNode){ -dijit.hideTooltip(this._connectNode); -delete this._connectNode; -this.onHide(); -} -if(this._showTimer){ -clearTimeout(this._showTimer); -delete this._showTimer; -} -},onShow:function(_15,_16){ -},onHide:function(){ -},uninitialize:function(){ -this.close(); -this.inherited(arguments); -}}); -dijit.Tooltip.defaultPosition=["after","before"]; + +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: String|String[] + // Id of domNode(s) to attach the tooltip to. + // When user hovers over specified dom node, the tooltip will appear. + connectId: [], + + // position: String[] + // See description of `dijit.Tooltip.defaultPosition` for details on position parameter. + position: [], + + _setConnectIdAttr: function(/*String*/ newId){ + // summary: + // Connect to node(s) (specified by id) + + // Remove connections to old nodes (if there are any) + dojo.forEach(this._connections || [], function(nested){ + dojo.forEach(nested, dojo.hitch(this, "disconnect")); + }, this); + + // Make connections to nodes in newIds. + var ary = dojo.isArrayLike(newId) ? newId : (newId ? [newId] : []); + this._connections = dojo.map(ary, function(id){ + var node = dojo.byId(id); + return node ? [ + this.connect(node, "onmouseenter", "_onTargetMouseEnter"), + this.connect(node, "onmouseleave", "_onTargetMouseLeave"), + this.connect(node, "onfocus", "_onTargetFocus"), + this.connect(node, "onblur", "_onTargetBlur") + ] : []; + }, this); + + this._set("connectId", newId); + + this._connectIds = ary; // save as array + }, + + addTarget: function(/*DOMNODE || String*/ node){ + // summary: + // Attach tooltip to specified node if it's not already connected + + // TODO: remove in 2.0 and just use set("connectId", ...) interface + + var id = node.id || node; + if(dojo.indexOf(this._connectIds, id) == -1){ + this.set("connectId", this._connectIds.concat(id)); + } + }, + + removeTarget: function(/*DOMNODE || String*/ node){ + // summary: + // Detach tooltip from specified node + + // TODO: remove in 2.0 and just use set("connectId", ...) interface + + var id = node.id || node, // map from DOMNode back to plain id string + idx = dojo.indexOf(this._connectIds, id); + if(idx >= 0){ + // remove id (modifies original this._connectIds but that's OK in this case) + this._connectIds.splice(idx, 1); + this.set("connectId", this._connectIds); + } + }, + + buildRendering: function(){ + this.inherited(arguments); + 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(); + }, + + open: function(/*DomNode*/ target){ + // summary: + // Display the tooltip; usually not called directly. + // tags: + // private + + if(this._showTimer){ + clearTimeout(this._showTimer); + delete this._showTimer; + } + dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight()); + + this._connectNode = target; + this.onShow(target, this.position); + }, + + 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; + this.onHide(); + } + if(this._showTimer){ + // if tooltip is scheduled to be shown (after a brief delay) + clearTimeout(this._showTimer); + delete this._showTimer; + } + }, + + onShow: function(target, position){ + // summary: + // Called when the tooltip is shown + // tags: + // callback + }, + + onHide: function(){ + // summary: + // Called when the tooltip is hidden + // tags: + // callback + }, + + uninitialize: function(){ + this.close(); + this.inherited(arguments); + } + } +); + +// 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"]; + } |