diff options
author | Andrew Dolgov <[email protected]> | 2013-03-18 10:26:24 +0400 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2013-03-18 10:26:26 +0400 |
commit | f0cfe83e3725f9a3928da97a6e3085e79cb25309 (patch) | |
tree | 4b0af188defaa807c7bc6ff3a101b41c9166c463 /lib/dijit/Tooltip.js.uncompressed.js | |
parent | 9a2885da170ffd64358b99194095851a2d09c1b6 (diff) |
upgrade dojo to 1.8.3 (refs #570)
Diffstat (limited to 'lib/dijit/Tooltip.js.uncompressed.js')
-rw-r--r-- | lib/dijit/Tooltip.js.uncompressed.js | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/lib/dijit/Tooltip.js.uncompressed.js b/lib/dijit/Tooltip.js.uncompressed.js new file mode 100644 index 000000000..3a181b360 --- /dev/null +++ b/lib/dijit/Tooltip.js.uncompressed.js @@ -0,0 +1,542 @@ +require({cache:{ +'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"}}); +define("dijit/Tooltip", [ + "dojo/_base/array", // array.forEach array.indexOf array.map + "dojo/_base/declare", // declare + "dojo/_base/fx", // fx.fadeIn fx.fadeOut + "dojo/dom", // dom.byId + "dojo/dom-class", // domClass.add + "dojo/dom-geometry", // domGeometry.position + "dojo/dom-style", // domStyle.set, domStyle.get + "dojo/_base/lang", // lang.hitch lang.isArrayLike + "dojo/mouse", + "dojo/on", + "dojo/sniff", // has("ie") + "./_base/manager", // manager.defaultDuration + "./place", + "./_Widget", + "./_TemplatedMixin", + "./BackgroundIframe", + "dojo/text!./templates/Tooltip.html", + "./main" // sets dijit.showTooltip etc. for back-compat +], function(array, declare, fx, dom, domClass, domGeometry, domStyle, lang, mouse, on, has, + manager, place, _Widget, _TemplatedMixin, BackgroundIframe, template, dijit){ + + // module: + // dijit/Tooltip + + + // TODO: Tooltip should really share more positioning code with TooltipDialog, like: + // - the orient() method + // - the connector positioning code in show() + // - the dijitTooltip[Dialog] class + // + // The problem is that Tooltip's implementation supplies it's own <iframe> and interacts directly + // with dijit/place, rather than going through dijit/popup like TooltipDialog and other popups (ex: Menu). + + var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], { + // 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: manager.defaultDuration, + + templateString: template, + + postCreate: function(){ + this.ownerDocumentBody.appendChild(this.domNode); + + this.bgIframe = new BackgroundIframe(this.domNode); + + // Setup fade-in and fade-out functions. + this.fadeIn = fx.fadeIn({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onShow") }); + this.fadeOut = fx.fadeOut({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onHide") }); + }, + + show: function(innerHTML, aroundNode, position, rtl, textDir){ + // 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) + // innerHTML: String + // Contents of the tooltip + // aroundNode: DomNode|dijit/place.__Rectangle + // Specifies that tooltip should be next to this node / area + // position: String[]? + // List of positions to try to position tooltip (ex: ["right", "above"]) + // rtl: Boolean? + // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true + // means "rtl"; specifies GUI direction, not text direction. + // textDir: String? + // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text. + + + if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){ + return; + } + + 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; + + if(textDir){ + this.set("textDir", textDir); + } + + this.containerNode.align = rtl? "right" : "left"; //fix the text alignment + + var pos = place.around(this.domNode, aroundNode, + position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient")); + + // Position the tooltip connector for middle alignment. + // This could not have been done in orient() since the tooltip wasn't positioned at that time. + var aroundNodeCoords = pos.aroundNodePos; + if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){ + this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px"; + this.connectorNode.style.left = ""; + }else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){ + this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px"; + }else{ + // Not *-centered, but just above/below/after/before + this.connectorNode.style.left = ""; + this.connectorNode.style.top = ""; + } + + // show it + domStyle.set(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 + + var heightAvailable = spaceAvailable.h, + widthAvailable = spaceAvailable.w; + + node.className = "dijitTooltip " + + { + "MR-ML": "dijitTooltipRight", + "ML-MR": "dijitTooltipLeft", + "TM-BM": "dijitTooltipAbove", + "BM-TM": "dijitTooltipBelow", + "BL-TL": "dijitTooltipBelow dijitTooltipABLeft", + "TL-BL": "dijitTooltipAbove dijitTooltipABLeft", + "BR-TR": "dijitTooltipBelow dijitTooltipABRight", + "TR-BR": "dijitTooltipAbove dijitTooltipABRight", + "BR-BL": "dijitTooltipRight", + "BL-BR": "dijitTooltipLeft" + }[aroundCorner + "-" + tooltipCorner]; + + // reset width; it may have been set by orient() on a previous tooltip show() + this.domNode.style.width = "auto"; + + // Reduce tooltip's width to the amount of width available, so that it doesn't overflow screen. + // Note that sometimes widthAvailable is negative, but we guard against setting style.width to a + // negative number since that causes an exception on IE. + var size = domGeometry.position(this.domNode); + if(has("ie") == 9){ + // workaround strange IE9 bug where setting width to offsetWidth causes words to wrap + size.w += 2; + } + + var width = Math.min((Math.max(widthAvailable,1)), size.w); + + domGeometry.setMarginBox(this.domNode, {w: width}); + + // Reposition the tooltip connector. + if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){ + var bb = domGeometry.position(node); + var tooltipConnectorHeight = this.connectorNode.offsetHeight; + if(bb.h > heightAvailable){ + // The tooltip starts at the top of the page and will extend past the aroundNode + var aroundNodePlacement = heightAvailable - ((aroundNodeCoords.h + tooltipConnectorHeight) >> 1); + 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), + bb.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 - widthAvailable); + }, + + _onShow: function(){ + // summary: + // Called at end of fade-in operation + // tags: + // protected + if(has("ie")){ + // 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; + } + }, + + _setAutoTextDir: function(/*Object*/node){ + // summary: + // Resolve "auto" text direction for children nodes + // tags: + // private + + this.applyTextDir(node, has("ie") ? node.outerText : node.textContent); + array.forEach(node.children, function(child){this._setAutoTextDir(child); }, this); + }, + + _setTextDirAttr: function(/*String*/ textDir){ + // summary: + // Setter for textDir. + // description: + // Users shouldn't call this function; they should be calling + // set('textDir', value) + // tags: + // private + + this._set("textDir", textDir); + + if (textDir == "auto"){ + this._setAutoTextDir(this.containerNode); + }else{ + this.containerNode.dir = this.textDir; + } + } + }); + + dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir){ + // summary: + // Static method to 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. + // innerHTML: String + // Contents of the tooltip + // aroundNode: place.__Rectangle + // Specifies that tooltip should be next to this node / area + // position: String[]? + // List of positions to try to position tooltip (ex: ["right", "above"]) + // rtl: Boolean? + // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true + // means "rtl"; specifies GUI direction, not text direction. + // textDir: String? + // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text. + + // After/before don't work, but for back-compat convert them to the working after-centered, before-centered. + // Possibly remove this in 2.0. Alternately, get before/after to work. + if(position){ + position = array.map(position, function(val){ + return {after: "after-centered", before: "before-centered"}[val] || val; + }); + } + + if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); } + return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir); + }; + + dijit.hideTooltip = function(aroundNode){ + // summary: + // Static method to hide the tooltip displayed via showTooltip() + return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode); + }; + + var Tooltip = declare("dijit.Tooltip", _Widget, { + // summary: + // Pops up a tooltip (a help message) when you hover over a node. + // Also provides static show() and hide() methods that can be used without instantiating a dijit/Tooltip. + + // 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[]|DomNode|DomNode[] + // Id of domNode(s) to attach the tooltip to. + // When user hovers over specified dom node(s), the tooltip will appear. + connectId: [], + + // position: String[] + // See description of `dijit/Tooltip.defaultPosition` for details on position parameter. + position: [], + + // selector: String? + // CSS expression to apply this Tooltip to descendants of connectIds, rather than to + // the nodes specified by connectIds themselves. Useful for applying a Tooltip to + // a range of rows in a table, tree, etc. Use in conjunction with getContent() parameter. + // Ex: connectId: myTable, selector: "tr", getContent: function(node){ return ...; } + // + // The application must require() an appropriate level of dojo/query to handle the selector. + selector: "", + + // TODO: in 2.0 remove support for multiple connectIds. selector gives the same effect. + // So, change connectId to a "", remove addTarget()/removeTarget(), etc. + + _setConnectIdAttr: function(/*String|String[]}DomNode|DomNode[]*/ newId){ + // summary: + // Connect to specified node(s) + + // Remove connections to old nodes (if there are any) + array.forEach(this._connections || [], function(nested){ + array.forEach(nested, function(handle){ handle.remove(); }); + }, this); + + // Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup() + this._connectIds = array.filter(lang.isArrayLike(newId) ? newId : (newId ? [newId] : []), + function(id){ return dom.byId(id, this.ownerDocument); }, this); + + // Make connections + this._connections = array.map(this._connectIds, function(id){ + var node = dom.byId(id, this.ownerDocument), + selector = this.selector, + delegatedEvent = selector ? + function(eventType){ return on.selector(selector, eventType); } : + function(eventType){ return eventType; }, + self = this; + return [ + on(node, delegatedEvent(mouse.enter), function(){ + self._onHover(this); + }), + on(node, delegatedEvent("focusin"), function(){ + self._onHover(this); + }), + on(node, delegatedEvent(mouse.leave), lang.hitch(self, "_onUnHover")), + on(node, delegatedEvent("focusout"), lang.hitch(self, "_onUnHover")) + ]; + }, this); + + this._set("connectId", newId); + }, + + addTarget: function(/*OomNode|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(array.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 = array.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); + domClass.add(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; + array.forEach(lang.isArrayLike(ids) ? ids : [ids], this.addTarget, this); + }, + + getContent: function(/*DomNode*/ node){ + // summary: + // User overridable function that return the text to display in the tooltip. + // tags: + // extension + return this.label || this.domNode.innerHTML; + }, + + _onHover: function(/*DomNode*/ target){ + // 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){ + this._showTimer = this.defer(function(){ this.open(target); }, this.showDelay); + } + }, + + _onUnHover: function(){ + // summary: + // Despite the name of this method, it actually handles both mouseleave and blur + // events on the target node, hiding the tooltip. + // tags: + // private + + if(this._showTimer){ + this._showTimer.remove(); + delete this._showTimer; + } + this.close(); + }, + + open: function(/*DomNode*/ target){ + // summary: + // Display the tooltip; usually not called directly. + // tags: + // private + + if(this._showTimer){ + this._showTimer.remove(); + delete this._showTimer; + } + + var content = this.getContent(target); + if(!content){ + return; + } + Tooltip.show(content, target, this.position, !this.isLeftToRight(), this.textDir); + + this._connectNode = target; // _connectNode means "tooltip currently displayed for this node" + 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 + Tooltip.hide(this._connectNode); + delete this._connectNode; + this.onHide(); + } + if(this._showTimer){ + // if tooltip is scheduled to be shown (after a brief delay) + this._showTimer.remove(); + 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 + }, + + destroy: function(){ + this.close(); + + // Remove connections manually since they aren't registered to be removed by _WidgetBase + array.forEach(this._connections || [], function(nested){ + array.forEach(nested, function(handle){ handle.remove(); }); + }, this); + + this.inherited(arguments); + } + }); + + Tooltip._MasterTooltip = MasterTooltip; // for monkey patching + Tooltip.show = dijit.showTooltip; // export function through module return value + Tooltip.hide = dijit.hideTooltip; // export function through module return value + + Tooltip.defaultPosition = ["after-centered", "before-centered"]; + + /*===== + lang.mixin(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 values + // possible for `dijit/place.around()`. The recommended values are: + // + // - before-centered: centers tooltip to the left of the anchor node/widget, or to the right + // in the case of RTL scripts like Hebrew and Arabic + // - after-centered: centers tooltip to the right of the anchor node/widget, or to the left + // in the case of RTL scripts like Hebrew and Arabic + // - above-centered: tooltip is centered above anchor node + // - below-centered: tooltip is centered above anchor 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-centered" 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. + }); + =====*/ + return Tooltip; +}); |