ToolTip.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:17k
源码类别:

中间件编程

开发平台:

JavaScript

  1. /*!  * Ext JS Library 3.0.0  * Copyright(c) 2006-2009 Ext JS, LLC  * licensing@extjs.com  * http://www.extjs.com/license  */ /**
  2.  * @class Ext.ToolTip
  3.  * @extends Ext.Tip
  4.  * A standard tooltip implementation for providing additional information when hovering over a target element.
  5.  * @constructor
  6.  * Create a new Tooltip
  7.  * @param {Object} config The configuration options
  8.  */
  9. Ext.ToolTip = Ext.extend(Ext.Tip, {
  10.     /**
  11.      * When a Tooltip is configured with the {@link #delegate} option to cause selected child elements of the {@link #target}
  12.      * Element to each trigger a seperate show event, this property is set to the DOM element which triggered the show.
  13.      * @type DOMElement
  14.      * @property triggerElement
  15.      */
  16.     /**
  17.      * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to monitor for mouseover events to trigger
  18.      * showing this ToolTip.
  19.      */
  20.     /**
  21.      * @cfg {Boolean} autoHide True to automatically hide the tooltip after the mouse exits the target element
  22.      * or after the {@link #dismissDelay} has expired if set (defaults to true).  If {@link closable} = true a close
  23.      * tool button will be rendered into the tooltip header.
  24.      */
  25.     /**
  26.      * @cfg {Number} showDelay Delay in milliseconds before the tooltip displays after the mouse enters the
  27.      * target element (defaults to 500)
  28.      */
  29.     showDelay: 500,
  30.     /**
  31.      * @cfg {Number} hideDelay Delay in milliseconds after the mouse exits the target element but before the
  32.      * tooltip actually hides (defaults to 200).  Set to 0 for the tooltip to hide immediately.
  33.      */
  34.     hideDelay: 200,
  35.     /**
  36.      * @cfg {Number} dismissDelay Delay in milliseconds before the tooltip automatically hides (defaults to 5000).
  37.      * To disable automatic hiding, set dismissDelay = 0.
  38.      */
  39.     dismissDelay: 5000,
  40.     /**
  41.      * @cfg {Array} mouseOffset An XY offset from the mouse position where the tooltip should be shown (defaults to [15,18]).
  42.      */
  43.     /**
  44.      * @cfg {Boolean} trackMouse True to have the tooltip follow the mouse as it moves over the target element (defaults to false).
  45.      */
  46.     trackMouse : false,
  47.     /**
  48.      * @cfg {Boolean} anchorToTarget True to anchor the tooltip to the target element, false to
  49.      * anchor it relative to the mouse coordinates (defaults to true).  When anchorToTarget is
  50.      * true, use {@link #defaultAlign} to control tooltip alignment to the target element.  When
  51.      * anchorToTarget is false, use {@link #anchorPosition} instead to control alignment.
  52.      */
  53.     anchorToTarget: true,
  54.     /**
  55.      * @cfg {Number} anchorOffset A numeric pixel value used to offset the default position of the
  56.      * anchor arrow (defaults to 0).  When the anchor position is on the top or bottom of the tooltip,
  57.      * anchorOffset will be used as a horizontal offset.  Likewise, when the anchor position is on the
  58.      * left or right side, anchorOffset will be used as a vertical offset.
  59.      */
  60.     anchorOffset: 0,
  61.     /**
  62.      * @cfg {String} delegate <p>Optional. A {@link Ext.DomQuery DomQuery} selector which allows selection of individual elements
  63.      * within the {@link #target} element to trigger showing and hiding the ToolTip as the mouse moves within the target.</p>
  64.      * <p>When specified, the child element of the target which caused a show event is placed into the {@link #triggerElement} property
  65.      * before the ToolTip is shown.</p>
  66.      * <p>This may be useful when a Component has regular, repeating elements in it, each of which need a Tooltip which contains
  67.      * information specific to that element. For example:</p><pre><code>
  68. var myGrid = new Ext.grid.gridPanel(gridConfig);
  69. myGrid.on('render', function(grid) {
  70.     var store = grid.getStore();  // Capture the Store.
  71.     var view = grid.getView();    // Capture the GridView.
  72.     myGrid.tip = new Ext.ToolTip({
  73.         target: view.mainBody,    // The overall target element.
  74.         delegate: '.x-grid3-row', // Each grid row causes its own seperate show and hide.
  75.         trackMouse: true,         // Moving within the row should not hide the tip.
  76.         renderTo: document.body,  // Render immediately so that tip.body can be referenced prior to the first show.
  77.         listeners: {              // Change content dynamically depending on which element triggered the show.
  78.             beforeshow: function updateTipBody(tip) {
  79.                 var rowIndex = view.findRowIndex(tip.triggerElement);
  80.                 tip.body.dom.innerHTML = "Over Record ID " + store.getAt(rowIndex).id;
  81.             }
  82.         }
  83.     });
  84. });</code></pre>
  85.      */
  86.     // private
  87.     targetCounter: 0,
  88.     constrainPosition: false,
  89.     // private
  90.     initComponent: function(){
  91.         Ext.ToolTip.superclass.initComponent.call(this);
  92.         this.lastActive = new Date();
  93.         this.initTarget(this.target);
  94.         this.origAnchor = this.anchor;
  95.     },
  96.     // private
  97.     onRender : function(ct, position){
  98.         Ext.ToolTip.superclass.onRender.call(this, ct, position);
  99.         this.anchorCls = 'x-tip-anchor-' + this.getAnchorPosition();
  100.         this.anchorEl = this.el.createChild({
  101.             cls: 'x-tip-anchor ' + this.anchorCls
  102.         });
  103.     },
  104.     // private
  105.     afterRender : function(){
  106.         Ext.ToolTip.superclass.afterRender.call(this);
  107.         this.anchorEl.setStyle('z-index', this.el.getZIndex() + 1);
  108.     },
  109.     /**
  110.      * Binds this ToolTip to the specified element. The tooltip will be displayed when the mouse moves over the element.
  111.      * @param {Mixed} t The Element, HtmlElement, or ID of an element to bind to
  112.      */
  113.     initTarget : function(target){
  114.         var t;
  115.         if((t = Ext.get(target))){
  116.             if(this.target){
  117.                 this.target = Ext.get(this.target);
  118.                 this.target.un('mouseover', this.onTargetOver, this);
  119.                 this.target.un('mouseout', this.onTargetOut, this);
  120.                 this.target.un('mousemove', this.onMouseMove, this);
  121.             }
  122.             this.mon(t, {
  123.                 mouseover: this.onTargetOver,
  124.                 mouseout: this.onTargetOut,
  125.                 mousemove: this.onMouseMove,
  126.                 scope: this
  127.             });
  128.             this.target = t;
  129.         }
  130.         if(this.anchor){
  131.             this.anchorTarget = this.target;
  132.         }
  133.     },
  134.     // private
  135.     onMouseMove : function(e){
  136.         var t = this.delegate ? e.getTarget(this.delegate) : this.triggerElement = true;
  137.         if (t) {
  138.             this.targetXY = e.getXY();
  139.             if (t === this.triggerElement) {
  140.                 if(!this.hidden && this.trackMouse){
  141.                     this.setPagePosition(this.getTargetXY());
  142.                 }
  143.             } else {
  144.                 this.hide();
  145.                 this.lastActive = new Date(0);
  146.                 this.onTargetOver(e);
  147.             }
  148.         } else if (!this.closable && this.isVisible()) {
  149.             this.hide();
  150.         }
  151.     },
  152.     // private
  153.     getTargetXY : function(){
  154.         if(this.anchor){
  155.             this.targetCounter++;
  156.             var offsets = this.getOffsets();
  157.             var xy = (this.anchorToTarget && !this.trackMouse) ?
  158.                 this.el.getAlignToXY(this.anchorTarget, this.getAnchorAlign()) :
  159.                 this.targetXY;
  160.             var dw = Ext.lib.Dom.getViewWidth()-5;
  161.             var dh = Ext.lib.Dom.getViewHeight()-5;
  162.             var scrollX = (document.documentElement.scrollLeft || document.body.scrollLeft || 0)+5;
  163.             var scrollY = (document.documentElement.scrollTop || document.body.scrollTop || 0)+5;
  164.             var axy = [xy[0] + offsets[0], xy[1] + offsets[1]];
  165.             var sz = this.getSize();
  166.             this.anchorEl.removeClass(this.anchorCls);
  167.             if(this.targetCounter < 2){
  168.                 if(axy[0] < scrollX){
  169.                     if(this.anchorToTarget){
  170.                         this.defaultAlign = 'l-r';
  171.                         if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  172.                     }
  173.                     this.anchor = 'left';
  174.                     return this.getTargetXY();
  175.                 }
  176.                 if(axy[0]+sz.width > dw){
  177.                     if(this.anchorToTarget){
  178.                         this.defaultAlign = 'r-l';
  179.                         if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  180.                     }
  181.                     this.anchor = 'right';
  182.                     return this.getTargetXY();
  183.                 }
  184.                 if(axy[1] < scrollY){
  185.                     if(this.anchorToTarget){
  186.                         this.defaultAlign = 't-b';
  187.                         if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  188.                     }
  189.                     this.anchor = 'top';
  190.                     return this.getTargetXY();
  191.                 }
  192.                 if(axy[1]+sz.height > dh){
  193.                     if(this.anchorToTarget){
  194.                         this.defaultAlign = 'b-t';
  195.                         if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  196.                     }
  197.                     this.anchor = 'bottom';
  198.                     return this.getTargetXY();
  199.                 }
  200.             }
  201.             this.anchorCls = 'x-tip-anchor-'+this.getAnchorPosition();
  202.             this.anchorEl.addClass(this.anchorCls);
  203.             this.targetCounter = 0;
  204.             return axy;
  205.         }else{
  206.             var mouseOffset = this.getMouseOffset();
  207.             return [this.targetXY[0]+mouseOffset[0], this.targetXY[1]+mouseOffset[1]];
  208.         }
  209.     },
  210.     getMouseOffset : function(){
  211.         var offset = this.anchor ? [0,0] : [15,18];
  212.         if(this.mouseOffset){
  213.             offset[0] += this.mouseOffset[0];
  214.             offset[1] += this.mouseOffset[1];
  215.         }
  216.         return offset;
  217.     },
  218.     // private
  219.     getAnchorPosition : function(){
  220.         if(this.anchor){
  221.             this.tipAnchor = this.anchor.charAt(0);
  222.         }else{
  223.             var m = this.defaultAlign.match(/^([a-z]+)-([a-z]+)(?)?$/);
  224.             if(!m){
  225.                throw "AnchorTip.defaultAlign is invalid";
  226.             }
  227.             this.tipAnchor = m[1].charAt(0);
  228.         }
  229.         switch(this.tipAnchor){
  230.             case 't': return 'top';
  231.             case 'b': return 'bottom';
  232.             case 'r': return 'right';
  233.         }
  234.         return 'left';
  235.     },
  236.     // private
  237.     getAnchorAlign : function(){
  238.         switch(this.anchor){
  239.             case 'top'  : return 'tl-bl';
  240.             case 'left' : return 'tl-tr';
  241.             case 'right': return 'tr-tl';
  242.             default     : return 'bl-tl';
  243.         }
  244.     },
  245.     // private
  246.     getOffsets: function(){
  247.         var offsets, ap = this.getAnchorPosition().charAt(0);
  248.         if(this.anchorToTarget && !this.trackMouse){
  249.             switch(ap){
  250.                 case 't':
  251.                     offsets = [0, 9];
  252.                     break;
  253.                 case 'b':
  254.                     offsets = [0, -13];
  255.                     break;
  256.                 case 'r':
  257.                     offsets = [-13, 0];
  258.                     break;
  259.                 default:
  260.                     offsets = [9, 0];
  261.                     break;
  262.             }
  263.         }else{
  264.             switch(ap){
  265.                 case 't':
  266.                     offsets = [-15-this.anchorOffset, 30];
  267.                     break;
  268.                 case 'b':
  269.                     offsets = [-19-this.anchorOffset, -13-this.el.dom.offsetHeight];
  270.                     break;
  271.                 case 'r':
  272.                     offsets = [-15-this.el.dom.offsetWidth, -13-this.anchorOffset];
  273.                     break;
  274.                 default:
  275.                     offsets = [25, -13-this.anchorOffset];
  276.                     break;
  277.             }
  278.         }
  279.         var mouseOffset = this.getMouseOffset();
  280.         offsets[0] += mouseOffset[0];
  281.         offsets[1] += mouseOffset[1];
  282.         return offsets;
  283.     },
  284.     // private
  285.     onTargetOver : function(e){
  286.         if(this.disabled || e.within(this.target.dom, true)){
  287.             return;
  288.         }
  289.         var t = e.getTarget(this.delegate);
  290.         if (t) {
  291.             this.triggerElement = t;
  292.             this.clearTimer('hide');
  293.             this.targetXY = e.getXY();
  294.             this.delayShow();
  295.         }
  296.     },
  297.     // private
  298.     delayShow : function(){
  299.         if(this.hidden && !this.showTimer){
  300.             if(this.lastActive.getElapsed() < this.quickShowInterval){
  301.                 this.show();
  302.             }else{
  303.                 this.showTimer = this.show.defer(this.showDelay, this);
  304.             }
  305.         }else if(!this.hidden && this.autoHide !== false){
  306.             this.show();
  307.         }
  308.     },
  309.     // private
  310.     onTargetOut : function(e){
  311.         if(this.disabled || e.within(this.target.dom, true)){
  312.             return;
  313.         }
  314.         this.clearTimer('show');
  315.         if(this.autoHide !== false){
  316.             this.delayHide();
  317.         }
  318.     },
  319.     // private
  320.     delayHide : function(){
  321.         if(!this.hidden && !this.hideTimer){
  322.             this.hideTimer = this.hide.defer(this.hideDelay, this);
  323.         }
  324.     },
  325.     /**
  326.      * Hides this tooltip if visible.
  327.      */
  328.     hide: function(){
  329.         this.clearTimer('dismiss');
  330.         this.lastActive = new Date();
  331.         if(this.anchorEl){
  332.             this.anchorEl.hide();
  333.         }
  334.         Ext.ToolTip.superclass.hide.call(this);
  335.         delete this.triggerElement;
  336.     },
  337.     /**
  338.      * Shows this tooltip at the current event target XY position.
  339.      */
  340.     show : function(){
  341.         if(this.anchor){
  342.             // pre-show it off screen so that the el will have dimensions
  343.             // for positioning calcs when getting xy next
  344.             this.showAt([-1000,-1000]);
  345.             this.origConstrainPosition = this.constrainPosition;
  346.             this.constrainPosition = false;
  347.             this.anchor = this.origAnchor;
  348.         }
  349.         this.showAt(this.getTargetXY());
  350.         if(this.anchor){
  351.             this.syncAnchor();
  352.             this.anchorEl.show();
  353.             this.constrainPosition = this.origConstrainPosition;
  354.         }else{
  355.             this.anchorEl.hide();
  356.         }
  357.     },
  358.     // inherit docs
  359.     showAt : function(xy){
  360.         this.lastActive = new Date();
  361.         this.clearTimers();
  362.         Ext.ToolTip.superclass.showAt.call(this, xy);
  363.         if(this.dismissDelay && this.autoHide !== false){
  364.             this.dismissTimer = this.hide.defer(this.dismissDelay, this);
  365.         }
  366.     },
  367.     // private
  368.     syncAnchor : function(){
  369.         var anchorPos, targetPos, offset;
  370.         switch(this.tipAnchor.charAt(0)){
  371.             case 't':
  372.                 anchorPos = 'b';
  373.                 targetPos = 'tl';
  374.                 offset = [20+this.anchorOffset, 2];
  375.                 break;
  376.             case 'r':
  377.                 anchorPos = 'l';
  378.                 targetPos = 'tr';
  379.                 offset = [-2, 11+this.anchorOffset];
  380.                 break;
  381.             case 'b':
  382.                 anchorPos = 't';
  383.                 targetPos = 'bl';
  384.                 offset = [20+this.anchorOffset, -2];
  385.                 break;
  386.             default:
  387.                 anchorPos = 'r';
  388.                 targetPos = 'tl';
  389.                 offset = [2, 11+this.anchorOffset];
  390.                 break;
  391.         }
  392.         this.anchorEl.alignTo(this.el, anchorPos+'-'+targetPos, offset);
  393.     },
  394.     // private
  395.     setPagePosition : function(x, y){
  396.         Ext.ToolTip.superclass.setPagePosition.call(this, x, y);
  397.         if(this.anchor){
  398.             this.syncAnchor();
  399.         }
  400.     },
  401.     // private
  402.     clearTimer : function(name){
  403.         name = name + 'Timer';
  404.         clearTimeout(this[name]);
  405.         delete this[name];
  406.     },
  407.     // private
  408.     clearTimers : function(){
  409.         this.clearTimer('show');
  410.         this.clearTimer('dismiss');
  411.         this.clearTimer('hide');
  412.     },
  413.     // private
  414.     onShow : function(){
  415.         Ext.ToolTip.superclass.onShow.call(this);
  416.         Ext.getDoc().on('mousedown', this.onDocMouseDown, this);
  417.     },
  418.     // private
  419.     onHide : function(){
  420.         Ext.ToolTip.superclass.onHide.call(this);
  421.         Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  422.     },
  423.     // private
  424.     onDocMouseDown : function(e){
  425.         if(this.autoHide !== true && !this.closable && !e.within(this.el.dom)){
  426.             this.disable();
  427.             this.enable.defer(100, this);
  428.         }
  429.     },
  430.     // private
  431.     onDisable : function(){
  432.         this.clearTimers();
  433.         this.hide();
  434.     },
  435.     // private
  436.     adjustPosition : function(x, y){
  437.         if(this.contstrainPosition){
  438.             var ay = this.targetXY[1], h = this.getSize().height;
  439.             if(y <= ay && (y+h) >= ay){
  440.                 y = ay-h-5;
  441.             }
  442.         }
  443.         return {x : x, y: y};
  444.     },
  445.     // private
  446.     onDestroy : function(){
  447.         Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  448.         Ext.ToolTip.superclass.onDestroy.call(this);
  449.     }
  450. });