123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- /*
- Copyright (c) 2004-2012, 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"]){ //_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],
- {
- // 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(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: 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"];
- }
|