]> git.wh0rd.org - tt-rss.git/blobdiff - lib/dijit/Tooltip.js
upgrade Dojo to 1.6.1
[tt-rss.git] / lib / dijit / Tooltip.js
index fea9a0bc1a205afdc42e940ad93121a9c773d609..46b3a3805ec5f60d4d1fb72eee353d6625b7cde8 100644 (file)
 /*
-       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"];
+
 }