Tooltip.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* Copyright (c) Business Objects 2006. All rights reserved. */
  2. bobj.crv.Tooltip = {
  3. show: function(tipHtml, x, y, options) {
  4. options = MochiKit.Base.update({
  5. delay: 0.5, // delay before starting to show the tooltip
  6. duration: 0.5, // duration of fade in/out effect in seconds
  7. aspect: 2.0, // Ratio of width to height
  8. wrapThreshold: 200 // Min width in px before growing vertically
  9. }, options);
  10. this._options = options;
  11. this._tipHtml = tipHtml;
  12. this._x = x;
  13. this._y = y;
  14. if (!this._layer) {
  15. this._createLayer();
  16. this._delayedShow = MochiKit.Base.bind(this._delayedShow, this);
  17. this._delayedHide = MochiKit.Base.bind(this._delayedHide, this);
  18. }
  19. clearTimeout(this._timeoutId);
  20. this._timeoutId = setTimeout(this._delayedShow, options.delay * 1000);
  21. },
  22. _delayedShow: function() {
  23. if (this._effect) {
  24. this._effect.cancel();
  25. }
  26. var style = this._layer.style;
  27. if (!this._options._fastShow) {
  28. if (bobj.isString(this._tipHtml)) {
  29. this._layer.firstChild.innerHTML = this._tipHtml;
  30. }
  31. this._resize();
  32. bobj.placeElement(this._layer, this._x, this._y, false, false);
  33. }
  34. style.visibility = 'visible';
  35. this._effect = MochiKit.Visual.appear(this._layer, {duration: this._options.duration});
  36. },
  37. hide: function(options) {
  38. if (this._layer) {
  39. this._options = MochiKit.Base.update(this._options, options);
  40. clearTimeout(this._timeoutId);
  41. this._timeoutId = setTimeout(this._delayedHide, this._options.delay * 1000);
  42. }
  43. },
  44. _delayedHide: function() {
  45. if (this._effect) {
  46. this._effect.cancel();
  47. }
  48. var layer = this._layer;
  49. this._effect = MochiKit.Visual.fade(layer, {
  50. duration: this._options.duration,
  51. afterFinish: function(){layer.style.visibility = 'hidden';},
  52. afterFinishInternal: null //don't set display:none
  53. });
  54. },
  55. _elementConnections: {},
  56. setElementTooltip: function(elt, tipHtml, options) {
  57. var CONNECT = MochiKit.Signal.connect;
  58. if (elt) {
  59. if (elt.bobj_crv_tooltip_id) {
  60. this.removeElementTooltip(elt);
  61. }
  62. else {
  63. elt.bobj_crv_tooltip_id = bobj.uniqueId();
  64. }
  65. var idents = [];
  66. this._elementConnections[elt.bobj_crv_tooltip_id] = idents;
  67. var over = function(e) {
  68. var p = e.mouse().page;
  69. bobj.crv.Tooltip.show(tipHtml, p.x, p.y, options);
  70. };
  71. var out = function(e) {
  72. bobj.crv.Tooltip.hide(options);
  73. };
  74. idents.push(CONNECT(elt, 'onmouseover', over));
  75. idents.push(CONNECT(elt, 'onmouseout', out));
  76. }
  77. },
  78. removeElementTooltip: function(elt) {
  79. if (elt && elt.bobj_crv_tooltip_id) {
  80. var idents = this._elementConnections[elt.bobj_crv_tooltip_id];
  81. if (idents) {
  82. for (var i = 0, len = idents.length; i < len; ++i) {
  83. MochiKit.Signal.disconnect(idents[i]);
  84. }
  85. delete this._elementConnections[elt.bobj_crv_tooltip_id];
  86. }
  87. }
  88. },
  89. _createLayer: function() {
  90. var CONNECT = MochiKit.Signal.connect;
  91. var DIV = MochiKit.DOM.DIV;
  92. this._layer = DIV({'class': "crvTooltip",
  93. style:"visibility:hidden, position:absolute; display:block; top:0px; left:0px"},
  94. DIV(null, '&nbsp;'));
  95. MochiKit.DOM.setOpacity(this._layer, 0);
  96. document.body.appendChild(this._layer);
  97. var over = function(e) {
  98. if (bobj.crv.Tooltip._effect) {
  99. bobj.crv.Tooltip.show(null, null, null,
  100. MochiKit.Base.update({_fastShow: true}, bobj.crv.Tooltip._options));
  101. }
  102. };
  103. var out = function(e) {
  104. bobj.crv.Tooltip.hide(bobj.crv.Tooltip._options);
  105. };
  106. CONNECT(this._layer, 'onmouseover', over);
  107. CONNECT(this._layer, 'onmouseout', out);
  108. },
  109. _resize: function() {
  110. var layer = this._layer;
  111. var layerStyle = layer.style;
  112. var content = layer.firstChild;
  113. var aspect = this._options.aspect;
  114. var wrapThreshold = this._options.wrapThreshold;
  115. var oldLeft = layerStyle.left;
  116. layerStyle.visibility = "hidden";
  117. layerStyle.left = '-' + wrapThreshold + 'px';
  118. layerStyle.width = null;
  119. layerStyle.height = null;
  120. if (content.offsetWidth > wrapThreshold) {
  121. var paddingY = parseInt(MochiKit.Style.computedStyle(layer, 'padding-top'), 10) || 0;
  122. paddingY += parseInt(MochiKit.Style.computedStyle(layer, 'padding-bottom'), 10) || 0;
  123. var paddingX = parseInt(MochiKit.Style.computedStyle(layer, 'padding-left'), 10) || 0;
  124. paddingX += parseInt(MochiKit.Style.computedStyle(layer, 'padding-right'), 10) || 0;
  125. //force overflow to get the smallest possible content width
  126. layerStyle.width = '1px';
  127. //now force reflow because some browsers will not fill the available
  128. //width otherwise (IE7)
  129. layerStyle.width = (content.offsetWidth + paddingX) +'px';
  130. content.innerHTML += '';
  131. var contentArea = content.offsetWidth * content.offsetHeight;
  132. var height = Math.ceil(Math.sqrt(contentArea / aspect));
  133. var width = height * aspect;
  134. layerStyle.height = height + paddingY + 'px';
  135. layerStyle.width = width + 'px';
  136. while(content.offsetWidth > layer.clientWidth ||
  137. content.offsetHeight > layer.clientHeight) {
  138. height += 5;
  139. width = height * aspect;
  140. layerStyle.height = height + 'px';
  141. layerStyle.width = width + 'px';
  142. }
  143. }
  144. layerStyle.left = oldLeft || null; //setting "" doesn't always work
  145. }
  146. };