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

中间件编程

开发平台:

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.Tip
  3.  * @extends Ext.Panel
  4.  * This is the base class for {@link Ext.QuickTip} and {@link Ext.Tooltip} that provides the basic layout and
  5.  * positioning that all tip-based classes require. This class can be used directly for simple, statically-positioned
  6.  * tips that are displayed programmatically, or it can be extended to provide custom tip implementations.
  7.  * @constructor
  8.  * Create a new Tip
  9.  * @param {Object} config The configuration options
  10.  */
  11. Ext.Tip = Ext.extend(Ext.Panel, {
  12.     /**
  13.      * @cfg {Boolean} closable True to render a close tool button into the tooltip header (defaults to false).
  14.      */
  15.     /**
  16.      * @cfg {Number} width
  17.      * Width in pixels of the tip (defaults to auto).  Width will be ignored if it exceeds the bounds of
  18.      * {@link #minWidth} or {@link #maxWidth}.  The maximum supported value is 500.
  19.      */
  20.     /**
  21.      * @cfg {Number} minWidth The minimum width of the tip in pixels (defaults to 40).
  22.      */
  23.     minWidth : 40,
  24.     /**
  25.      * @cfg {Number} maxWidth The maximum width of the tip in pixels (defaults to 300).  The maximum supported value is 500.
  26.      */
  27.     maxWidth : 300,
  28.     /**
  29.      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
  30.      * for bottom-right shadow (defaults to "sides").
  31.      */
  32.     shadow : "sides",
  33.     /**
  34.      * @cfg {String} defaultAlign <b>Experimental</b>. The default {@link Ext.Element#alignTo} anchor position value
  35.      * for this tip relative to its element of origin (defaults to "tl-bl?").
  36.      */
  37.     defaultAlign : "tl-bl?",
  38.     autoRender: true,
  39.     quickShowInterval : 250,
  40.     // private panel overrides
  41.     frame:true,
  42.     hidden:true,
  43.     baseCls: 'x-tip',
  44.     floating:{shadow:true,shim:true,useDisplay:true,constrain:false},
  45.     autoHeight:true,
  46.     closeAction: 'hide',
  47.     // private
  48.     initComponent : function(){
  49.         Ext.Tip.superclass.initComponent.call(this);
  50.         if(this.closable && !this.title){
  51.             this.elements += ',header';
  52.         }
  53.     },
  54.     // private
  55.     afterRender : function(){
  56.         Ext.Tip.superclass.afterRender.call(this);
  57.         if(this.closable){
  58.             this.addTool({
  59.                 id: 'close',
  60.                 handler: this[this.closeAction],
  61.                 scope: this
  62.             });
  63.         }
  64.     },
  65.     /**
  66.      * Shows this tip at the specified XY position.  Example usage:
  67.      * <pre><code>
  68. // Show the tip at x:50 and y:100
  69. tip.showAt([50,100]);
  70. </code></pre>
  71.      * @param {Array} xy An array containing the x and y coordinates
  72.      */
  73.     showAt : function(xy){
  74.         Ext.Tip.superclass.show.call(this);
  75.         if(this.measureWidth !== false && (!this.initialConfig || typeof this.initialConfig.width != 'number')){
  76.             this.doAutoWidth();
  77.         }
  78.         if(this.constrainPosition){
  79.             xy = this.el.adjustForConstraints(xy);
  80.         }
  81.         this.setPagePosition(xy[0], xy[1]);
  82.     },
  83.     // protected
  84.     doAutoWidth : function(){
  85.         var bw = this.body.getTextWidth();
  86.         if(this.title){
  87.             bw = Math.max(bw, this.header.child('span').getTextWidth(this.title));
  88.         }
  89.         bw += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr");
  90.         this.setWidth(bw.constrain(this.minWidth, this.maxWidth));
  91.         
  92.         // IE7 repaint bug on initial show
  93.         if(Ext.isIE7 && !this.repainted){
  94.             this.el.repaint();
  95.             this.repainted = true;
  96.         }
  97.     },
  98.     /**
  99.      * <b>Experimental</b>. Shows this tip at a position relative to another element using a standard {@link Ext.Element#alignTo}
  100.      * anchor position value.  Example usage:
  101.      * <pre><code>
  102. // Show the tip at the default position ('tl-br?')
  103. tip.showBy('my-el');
  104. // Show the tip's top-left corner anchored to the element's top-right corner
  105. tip.showBy('my-el', 'tl-tr');
  106. </code></pre>
  107.      * @param {Mixed} el An HTMLElement, Ext.Element or string id of the target element to align to
  108.      * @param {String} position (optional) A valid {@link Ext.Element#alignTo} anchor position (defaults to 'tl-br?' or
  109.      * {@link #defaultAlign} if specified).
  110.      */
  111.     showBy : function(el, pos){
  112.         if(!this.rendered){
  113.             this.render(Ext.getBody());
  114.         }
  115.         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign));
  116.     },
  117.     initDraggable : function(){
  118.         this.dd = new Ext.Tip.DD(this, typeof this.draggable == 'boolean' ? null : this.draggable);
  119.         this.header.addClass('x-tip-draggable');
  120.     }
  121. });
  122. // private - custom Tip DD implementation
  123. Ext.Tip.DD = function(tip, config){
  124.     Ext.apply(this, config);
  125.     this.tip = tip;
  126.     Ext.Tip.DD.superclass.constructor.call(this, tip.el.id, 'WindowDD-'+tip.id);
  127.     this.setHandleElId(tip.header.id);
  128.     this.scroll = false;
  129. };
  130. Ext.extend(Ext.Tip.DD, Ext.dd.DD, {
  131.     moveOnly:true,
  132.     scroll:false,
  133.     headerOffsets:[100, 25],
  134.     startDrag : function(){
  135.         this.tip.el.disableShadow();
  136.     },
  137.     endDrag : function(e){
  138.         this.tip.el.enableShadow(true);
  139.     }
  140. });/**
  141.  * @class Ext.ToolTip
  142.  * @extends Ext.Tip
  143.  * A standard tooltip implementation for providing additional information when hovering over a target element.
  144.  * @constructor
  145.  * Create a new Tooltip
  146.  * @param {Object} config The configuration options
  147.  */
  148. Ext.ToolTip = Ext.extend(Ext.Tip, {
  149.     /**
  150.      * When a Tooltip is configured with the {@link #delegate} option to cause selected child elements of the {@link #target}
  151.      * Element to each trigger a seperate show event, this property is set to the DOM element which triggered the show.
  152.      * @type DOMElement
  153.      * @property triggerElement
  154.      */
  155.     /**
  156.      * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to monitor for mouseover events to trigger
  157.      * showing this ToolTip.
  158.      */
  159.     /**
  160.      * @cfg {Boolean} autoHide True to automatically hide the tooltip after the mouse exits the target element
  161.      * or after the {@link #dismissDelay} has expired if set (defaults to true).  If {@link closable} = true a close
  162.      * tool button will be rendered into the tooltip header.
  163.      */
  164.     /**
  165.      * @cfg {Number} showDelay Delay in milliseconds before the tooltip displays after the mouse enters the
  166.      * target element (defaults to 500)
  167.      */
  168.     showDelay: 500,
  169.     /**
  170.      * @cfg {Number} hideDelay Delay in milliseconds after the mouse exits the target element but before the
  171.      * tooltip actually hides (defaults to 200).  Set to 0 for the tooltip to hide immediately.
  172.      */
  173.     hideDelay: 200,
  174.     /**
  175.      * @cfg {Number} dismissDelay Delay in milliseconds before the tooltip automatically hides (defaults to 5000).
  176.      * To disable automatic hiding, set dismissDelay = 0.
  177.      */
  178.     dismissDelay: 5000,
  179.     /**
  180.      * @cfg {Array} mouseOffset An XY offset from the mouse position where the tooltip should be shown (defaults to [15,18]).
  181.      */
  182.     /**
  183.      * @cfg {Boolean} trackMouse True to have the tooltip follow the mouse as it moves over the target element (defaults to false).
  184.      */
  185.     trackMouse : false,
  186.     /**
  187.      * @cfg {Boolean} anchorToTarget True to anchor the tooltip to the target element, false to
  188.      * anchor it relative to the mouse coordinates (defaults to true).  When anchorToTarget is
  189.      * true, use {@link #defaultAlign} to control tooltip alignment to the target element.  When
  190.      * anchorToTarget is false, use {@link #anchorPosition} instead to control alignment.
  191.      */
  192.     anchorToTarget: true,
  193.     /**
  194.      * @cfg {Number} anchorOffset A numeric pixel value used to offset the default position of the
  195.      * anchor arrow (defaults to 0).  When the anchor position is on the top or bottom of the tooltip,
  196.      * anchorOffset will be used as a horizontal offset.  Likewise, when the anchor position is on the
  197.      * left or right side, anchorOffset will be used as a vertical offset.
  198.      */
  199.     anchorOffset: 0,
  200.     /**
  201.      * @cfg {String} delegate <p>Optional. A {@link Ext.DomQuery DomQuery} selector which allows selection of individual elements
  202.      * within the {@link #target} element to trigger showing and hiding the ToolTip as the mouse moves within the target.</p>
  203.      * <p>When specified, the child element of the target which caused a show event is placed into the {@link #triggerElement} property
  204.      * before the ToolTip is shown.</p>
  205.      * <p>This may be useful when a Component has regular, repeating elements in it, each of which need a Tooltip which contains
  206.      * information specific to that element. For example:</p><pre><code>
  207. var myGrid = new Ext.grid.gridPanel(gridConfig);
  208. myGrid.on('render', function(grid) {
  209.     var store = grid.getStore();  // Capture the Store.
  210.     var view = grid.getView();    // Capture the GridView.
  211.     myGrid.tip = new Ext.ToolTip({
  212.         target: view.mainBody,    // The overall target element.
  213.         delegate: '.x-grid3-row', // Each grid row causes its own seperate show and hide.
  214.         trackMouse: true,         // Moving within the row should not hide the tip.
  215.         renderTo: document.body,  // Render immediately so that tip.body can be referenced prior to the first show.
  216.         listeners: {              // Change content dynamically depending on which element triggered the show.
  217.             beforeshow: function updateTipBody(tip) {
  218.                 var rowIndex = view.findRowIndex(tip.triggerElement);
  219.                 tip.body.dom.innerHTML = "Over Record ID " + store.getAt(rowIndex).id;
  220.             }
  221.         }
  222.     });
  223. });</code></pre>
  224.      */
  225.     // private
  226.     targetCounter: 0,
  227.     constrainPosition: false,
  228.     // private
  229.     initComponent: function(){
  230.         Ext.ToolTip.superclass.initComponent.call(this);
  231.         this.lastActive = new Date();
  232.         this.initTarget(this.target);
  233.         this.origAnchor = this.anchor;
  234.     },
  235.     // private
  236.     onRender : function(ct, position){
  237.         Ext.ToolTip.superclass.onRender.call(this, ct, position);
  238.         this.anchorCls = 'x-tip-anchor-' + this.getAnchorPosition();
  239.         this.anchorEl = this.el.createChild({
  240.             cls: 'x-tip-anchor ' + this.anchorCls
  241.         });
  242.     },
  243.     // private
  244.     afterRender : function(){
  245.         Ext.ToolTip.superclass.afterRender.call(this);
  246.         this.anchorEl.setStyle('z-index', this.el.getZIndex() + 1);
  247.     },
  248.     /**
  249.      * Binds this ToolTip to the specified element. The tooltip will be displayed when the mouse moves over the element.
  250.      * @param {Mixed} t The Element, HtmlElement, or ID of an element to bind to
  251.      */
  252.     initTarget : function(target){
  253.         var t;
  254.         if((t = Ext.get(target))){
  255.             if(this.target){
  256.                 this.target = Ext.get(this.target);
  257.                 this.target.un('mouseover', this.onTargetOver, this);
  258.                 this.target.un('mouseout', this.onTargetOut, this);
  259.                 this.target.un('mousemove', this.onMouseMove, this);
  260.             }
  261.             this.mon(t, {
  262.                 mouseover: this.onTargetOver,
  263.                 mouseout: this.onTargetOut,
  264.                 mousemove: this.onMouseMove,
  265.                 scope: this
  266.             });
  267.             this.target = t;
  268.         }
  269.         if(this.anchor){
  270.             this.anchorTarget = this.target;
  271.         }
  272.     },
  273.     // private
  274.     onMouseMove : function(e){
  275.         var t = this.delegate ? e.getTarget(this.delegate) : this.triggerElement = true;
  276.         if (t) {
  277.             this.targetXY = e.getXY();
  278.             if (t === this.triggerElement) {
  279.                 if(!this.hidden && this.trackMouse){
  280.                     this.setPagePosition(this.getTargetXY());
  281.                 }
  282.             } else {
  283.                 this.hide();
  284.                 this.lastActive = new Date(0);
  285.                 this.onTargetOver(e);
  286.             }
  287.         } else if (!this.closable && this.isVisible()) {
  288.             this.hide();
  289.         }
  290.     },
  291.     // private
  292.     getTargetXY : function(){
  293.         if(this.anchor){
  294.             this.targetCounter++;
  295.             var offsets = this.getOffsets();
  296.             var xy = (this.anchorToTarget && !this.trackMouse) ?
  297.                 this.el.getAlignToXY(this.anchorTarget, this.getAnchorAlign()) :
  298.                 this.targetXY;
  299.             var dw = Ext.lib.Dom.getViewWidth()-5;
  300.             var dh = Ext.lib.Dom.getViewHeight()-5;
  301.             var scrollX = (document.documentElement.scrollLeft || document.body.scrollLeft || 0)+5;
  302.             var scrollY = (document.documentElement.scrollTop || document.body.scrollTop || 0)+5;
  303.             var axy = [xy[0] + offsets[0], xy[1] + offsets[1]];
  304.             var sz = this.getSize();
  305.             this.anchorEl.removeClass(this.anchorCls);
  306.             if(this.targetCounter < 2){
  307.                 if(axy[0] < scrollX){
  308.                     if(this.anchorToTarget){
  309.                         this.defaultAlign = 'l-r';
  310.                         if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  311.                     }
  312.                     this.anchor = 'left';
  313.                     return this.getTargetXY();
  314.                 }
  315.                 if(axy[0]+sz.width > dw){
  316.                     if(this.anchorToTarget){
  317.                         this.defaultAlign = 'r-l';
  318.                         if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  319.                     }
  320.                     this.anchor = 'right';
  321.                     return this.getTargetXY();
  322.                 }
  323.                 if(axy[1] < scrollY){
  324.                     if(this.anchorToTarget){
  325.                         this.defaultAlign = 't-b';
  326.                         if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  327.                     }
  328.                     this.anchor = 'top';
  329.                     return this.getTargetXY();
  330.                 }
  331.                 if(axy[1]+sz.height > dh){
  332.                     if(this.anchorToTarget){
  333.                         this.defaultAlign = 'b-t';
  334.                         if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  335.                     }
  336.                     this.anchor = 'bottom';
  337.                     return this.getTargetXY();
  338.                 }
  339.             }
  340.             this.anchorCls = 'x-tip-anchor-'+this.getAnchorPosition();
  341.             this.anchorEl.addClass(this.anchorCls);
  342.             this.targetCounter = 0;
  343.             return axy;
  344.         }else{
  345.             var mouseOffset = this.getMouseOffset();
  346.             return [this.targetXY[0]+mouseOffset[0], this.targetXY[1]+mouseOffset[1]];
  347.         }
  348.     },
  349.     getMouseOffset : function(){
  350.         var offset = this.anchor ? [0,0] : [15,18];
  351.         if(this.mouseOffset){
  352.             offset[0] += this.mouseOffset[0];
  353.             offset[1] += this.mouseOffset[1];
  354.         }
  355.         return offset;
  356.     },
  357.     // private
  358.     getAnchorPosition : function(){
  359.         if(this.anchor){
  360.             this.tipAnchor = this.anchor.charAt(0);
  361.         }else{
  362.             var m = this.defaultAlign.match(/^([a-z]+)-([a-z]+)(?)?$/);
  363.             if(!m){
  364.                throw "AnchorTip.defaultAlign is invalid";
  365.             }
  366.             this.tipAnchor = m[1].charAt(0);
  367.         }
  368.         switch(this.tipAnchor){
  369.             case 't': return 'top';
  370.             case 'b': return 'bottom';
  371.             case 'r': return 'right';
  372.         }
  373.         return 'left';
  374.     },
  375.     // private
  376.     getAnchorAlign : function(){
  377.         switch(this.anchor){
  378.             case 'top'  : return 'tl-bl';
  379.             case 'left' : return 'tl-tr';
  380.             case 'right': return 'tr-tl';
  381.             default     : return 'bl-tl';
  382.         }
  383.     },
  384.     // private
  385.     getOffsets: function(){
  386.         var offsets, ap = this.getAnchorPosition().charAt(0);
  387.         if(this.anchorToTarget && !this.trackMouse){
  388.             switch(ap){
  389.                 case 't':
  390.                     offsets = [0, 9];
  391.                     break;
  392.                 case 'b':
  393.                     offsets = [0, -13];
  394.                     break;
  395.                 case 'r':
  396.                     offsets = [-13, 0];
  397.                     break;
  398.                 default:
  399.                     offsets = [9, 0];
  400.                     break;
  401.             }
  402.         }else{
  403.             switch(ap){
  404.                 case 't':
  405.                     offsets = [-15-this.anchorOffset, 30];
  406.                     break;
  407.                 case 'b':
  408.                     offsets = [-19-this.anchorOffset, -13-this.el.dom.offsetHeight];
  409.                     break;
  410.                 case 'r':
  411.                     offsets = [-15-this.el.dom.offsetWidth, -13-this.anchorOffset];
  412.                     break;
  413.                 default:
  414.                     offsets = [25, -13-this.anchorOffset];
  415.                     break;
  416.             }
  417.         }
  418.         var mouseOffset = this.getMouseOffset();
  419.         offsets[0] += mouseOffset[0];
  420.         offsets[1] += mouseOffset[1];
  421.         return offsets;
  422.     },
  423.     // private
  424.     onTargetOver : function(e){
  425.         if(this.disabled || e.within(this.target.dom, true)){
  426.             return;
  427.         }
  428.         var t = e.getTarget(this.delegate);
  429.         if (t) {
  430.             this.triggerElement = t;
  431.             this.clearTimer('hide');
  432.             this.targetXY = e.getXY();
  433.             this.delayShow();
  434.         }
  435.     },
  436.     // private
  437.     delayShow : function(){
  438.         if(this.hidden && !this.showTimer){
  439.             if(this.lastActive.getElapsed() < this.quickShowInterval){
  440.                 this.show();
  441.             }else{
  442.                 this.showTimer = this.show.defer(this.showDelay, this);
  443.             }
  444.         }else if(!this.hidden && this.autoHide !== false){
  445.             this.show();
  446.         }
  447.     },
  448.     // private
  449.     onTargetOut : function(e){
  450.         if(this.disabled || e.within(this.target.dom, true)){
  451.             return;
  452.         }
  453.         this.clearTimer('show');
  454.         if(this.autoHide !== false){
  455.             this.delayHide();
  456.         }
  457.     },
  458.     // private
  459.     delayHide : function(){
  460.         if(!this.hidden && !this.hideTimer){
  461.             this.hideTimer = this.hide.defer(this.hideDelay, this);
  462.         }
  463.     },
  464.     /**
  465.      * Hides this tooltip if visible.
  466.      */
  467.     hide: function(){
  468.         this.clearTimer('dismiss');
  469.         this.lastActive = new Date();
  470.         if(this.anchorEl){
  471.             this.anchorEl.hide();
  472.         }
  473.         Ext.ToolTip.superclass.hide.call(this);
  474.         delete this.triggerElement;
  475.     },
  476.     /**
  477.      * Shows this tooltip at the current event target XY position.
  478.      */
  479.     show : function(){
  480.         if(this.anchor){
  481.             // pre-show it off screen so that the el will have dimensions
  482.             // for positioning calcs when getting xy next
  483.             this.showAt([-1000,-1000]);
  484.             this.origConstrainPosition = this.constrainPosition;
  485.             this.constrainPosition = false;
  486.             this.anchor = this.origAnchor;
  487.         }
  488.         this.showAt(this.getTargetXY());
  489.         if(this.anchor){
  490.             this.syncAnchor();
  491.             this.anchorEl.show();
  492.             this.constrainPosition = this.origConstrainPosition;
  493.         }else{
  494.             this.anchorEl.hide();
  495.         }
  496.     },
  497.     // inherit docs
  498.     showAt : function(xy){
  499.         this.lastActive = new Date();
  500.         this.clearTimers();
  501.         Ext.ToolTip.superclass.showAt.call(this, xy);
  502.         if(this.dismissDelay && this.autoHide !== false){
  503.             this.dismissTimer = this.hide.defer(this.dismissDelay, this);
  504.         }
  505.     },
  506.     // private
  507.     syncAnchor : function(){
  508.         var anchorPos, targetPos, offset;
  509.         switch(this.tipAnchor.charAt(0)){
  510.             case 't':
  511.                 anchorPos = 'b';
  512.                 targetPos = 'tl';
  513.                 offset = [20+this.anchorOffset, 2];
  514.                 break;
  515.             case 'r':
  516.                 anchorPos = 'l';
  517.                 targetPos = 'tr';
  518.                 offset = [-2, 11+this.anchorOffset];
  519.                 break;
  520.             case 'b':
  521.                 anchorPos = 't';
  522.                 targetPos = 'bl';
  523.                 offset = [20+this.anchorOffset, -2];
  524.                 break;
  525.             default:
  526.                 anchorPos = 'r';
  527.                 targetPos = 'tl';
  528.                 offset = [2, 11+this.anchorOffset];
  529.                 break;
  530.         }
  531.         this.anchorEl.alignTo(this.el, anchorPos+'-'+targetPos, offset);
  532.     },
  533.     // private
  534.     setPagePosition : function(x, y){
  535.         Ext.ToolTip.superclass.setPagePosition.call(this, x, y);
  536.         if(this.anchor){
  537.             this.syncAnchor();
  538.         }
  539.     },
  540.     // private
  541.     clearTimer : function(name){
  542.         name = name + 'Timer';
  543.         clearTimeout(this[name]);
  544.         delete this[name];
  545.     },
  546.     // private
  547.     clearTimers : function(){
  548.         this.clearTimer('show');
  549.         this.clearTimer('dismiss');
  550.         this.clearTimer('hide');
  551.     },
  552.     // private
  553.     onShow : function(){
  554.         Ext.ToolTip.superclass.onShow.call(this);
  555.         Ext.getDoc().on('mousedown', this.onDocMouseDown, this);
  556.     },
  557.     // private
  558.     onHide : function(){
  559.         Ext.ToolTip.superclass.onHide.call(this);
  560.         Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  561.     },
  562.     // private
  563.     onDocMouseDown : function(e){
  564.         if(this.autoHide !== true && !this.closable && !e.within(this.el.dom)){
  565.             this.disable();
  566.             this.enable.defer(100, this);
  567.         }
  568.     },
  569.     // private
  570.     onDisable : function(){
  571.         this.clearTimers();
  572.         this.hide();
  573.     },
  574.     // private
  575.     adjustPosition : function(x, y){
  576.         if(this.contstrainPosition){
  577.             var ay = this.targetXY[1], h = this.getSize().height;
  578.             if(y <= ay && (y+h) >= ay){
  579.                 y = ay-h-5;
  580.             }
  581.         }
  582.         return {x : x, y: y};
  583.     },
  584.     // private
  585.     onDestroy : function(){
  586.         Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  587.         Ext.ToolTip.superclass.onDestroy.call(this);
  588.     }
  589. });/**
  590.  * @class Ext.QuickTip
  591.  * @extends Ext.ToolTip
  592.  * A specialized tooltip class for tooltips that can be specified in markup and automatically managed by the global
  593.  * {@link Ext.QuickTips} instance.  See the QuickTips class header for additional usage details and examples.
  594.  * @constructor
  595.  * Create a new Tip
  596.  * @param {Object} config The configuration options
  597.  */
  598. Ext.QuickTip = Ext.extend(Ext.ToolTip, {
  599.     /**
  600.      * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to associate with this quicktip (defaults to the document).
  601.      */
  602.     /**
  603.      * @cfg {Boolean} interceptTitles True to automatically use the element's DOM title value if available (defaults to false).
  604.      */
  605.     interceptTitles : false,
  606.     // private
  607.     tagConfig : {
  608.         namespace : "ext",
  609.         attribute : "qtip",
  610.         width : "qwidth",
  611.         target : "target",
  612.         title : "qtitle",
  613.         hide : "hide",
  614.         cls : "qclass",
  615.         align : "qalign",
  616.         anchor : "anchor"
  617.     },
  618.     // private
  619.     initComponent : function(){
  620.         this.target = this.target || Ext.getDoc();
  621.         this.targets = this.targets || {};
  622.         Ext.QuickTip.superclass.initComponent.call(this);
  623.     },
  624.     /**
  625.      * Configures a new quick tip instance and assigns it to a target element.  The following config values are
  626.      * supported (for example usage, see the {@link Ext.QuickTips} class header):
  627.      * <div class="mdetail-params"><ul>
  628.      * <li>autoHide</li>
  629.      * <li>cls</li>
  630.      * <li>dismissDelay (overrides the singleton value)</li>
  631.      * <li>target (required)</li>
  632.      * <li>text (required)</li>
  633.      * <li>title</li>
  634.      * <li>width</li></ul></div>
  635.      * @param {Object} config The config object
  636.      */
  637.     register : function(config){
  638.         var cs = Ext.isArray(config) ? config : arguments;
  639.         for(var i = 0, len = cs.length; i < len; i++){
  640.             var c = cs[i];
  641.             var target = c.target;
  642.             if(target){
  643.                 if(Ext.isArray(target)){
  644.                     for(var j = 0, jlen = target.length; j < jlen; j++){
  645.                         this.targets[Ext.id(target[j])] = c;
  646.                     }
  647.                 } else{
  648.                     this.targets[Ext.id(target)] = c;
  649.                 }
  650.             }
  651.         }
  652.     },
  653.     /**
  654.      * Removes this quick tip from its element and destroys it.
  655.      * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
  656.      */
  657.     unregister : function(el){
  658.         delete this.targets[Ext.id(el)];
  659.     },
  660.     
  661.     /**
  662.      * Hides a visible tip or cancels an impending show for a particular element.
  663.      * @param {String/HTMLElement/Element} el The element that is the target of the tip.
  664.      */
  665.     cancelShow: function(el){
  666.         var at = this.activeTarget;
  667.         el = Ext.get(el).dom;
  668.         if(this.isVisible()){
  669.             if(at && at.el == el){
  670.                 this.hide();
  671.             }
  672.         }else if(at && at.el == el){
  673.             this.clearTimer('show');
  674.         }
  675.     },
  676.     // private
  677.     onTargetOver : function(e){
  678.         if(this.disabled){
  679.             return;
  680.         }
  681.         this.targetXY = e.getXY();
  682.         var t = e.getTarget();
  683.         if(!t || t.nodeType !== 1 || t == document || t == document.body){
  684.             return;
  685.         }
  686.         if(this.activeTarget && t == this.activeTarget.el){
  687.             this.clearTimer('hide');
  688.             this.show();
  689.             return;
  690.         }
  691.         if(t && this.targets[t.id]){
  692.             this.activeTarget = this.targets[t.id];
  693.             this.activeTarget.el = t;
  694.             this.anchor = this.activeTarget.anchor;
  695.             if(this.anchor){
  696.                 this.anchorTarget = t;
  697.             }
  698.             this.delayShow();
  699.             return;
  700.         }
  701.         
  702.         var ttp, et = Ext.fly(t), cfg = this.tagConfig;
  703.         var ns = cfg.namespace;
  704.         if(this.interceptTitles && t.title){
  705.             ttp = t.title;
  706.             t.qtip = ttp;
  707.             t.removeAttribute("title");
  708.             e.preventDefault();
  709.         } else{
  710.             ttp = t.qtip || et.getAttribute(cfg.attribute, ns);
  711.         }
  712.         if(ttp){
  713.             var autoHide = et.getAttribute(cfg.hide, ns);
  714.             this.activeTarget = {
  715.                 el: t,
  716.                 text: ttp,
  717.                 width: et.getAttribute(cfg.width, ns),
  718.                 autoHide: autoHide != "user" && autoHide !== 'false',
  719.                 title: et.getAttribute(cfg.title, ns),
  720.                 cls: et.getAttribute(cfg.cls, ns),
  721.                 align: et.getAttribute(cfg.align, ns)
  722.                 
  723.             };
  724.             this.anchor = et.getAttribute(cfg.anchor, ns);
  725.             if(this.anchor){
  726.                 this.anchorTarget = t;
  727.             }
  728.             this.delayShow();
  729.         }
  730.     },
  731.     // private
  732.     onTargetOut : function(e){
  733.         this.clearTimer('show');
  734.         if(this.autoHide !== false){
  735.             this.delayHide();
  736.         }
  737.     },
  738.     // inherit docs
  739.     showAt : function(xy){
  740.         var t = this.activeTarget;
  741.         if(t){
  742.             if(!this.rendered){
  743.                 this.render(Ext.getBody());
  744.                 this.activeTarget = t;
  745.             }
  746.             if(t.width){
  747.                 this.setWidth(t.width);
  748.                 this.body.setWidth(this.adjustBodyWidth(t.width - this.getFrameWidth()));
  749.                 this.measureWidth = false;
  750.             } else{
  751.                 this.measureWidth = true;
  752.             }
  753.             this.setTitle(t.title || '');
  754.             this.body.update(t.text);
  755.             this.autoHide = t.autoHide;
  756.             this.dismissDelay = t.dismissDelay || this.dismissDelay;
  757.             if(this.lastCls){
  758.                 this.el.removeClass(this.lastCls);
  759.                 delete this.lastCls;
  760.             }
  761.             if(t.cls){
  762.                 this.el.addClass(t.cls);
  763.                 this.lastCls = t.cls;
  764.             }
  765.             if(this.anchor){
  766.                 this.constrainPosition = false;
  767.             }else if(t.align){ // TODO: this doesn't seem to work consistently
  768.                 xy = this.el.getAlignToXY(t.el, t.align);
  769.                 this.constrainPosition = false;
  770.             }else{
  771.                 this.constrainPosition = true;
  772.             }
  773.         }
  774.         Ext.QuickTip.superclass.showAt.call(this, xy);
  775.     },
  776.     // inherit docs
  777.     hide: function(){
  778.         delete this.activeTarget;
  779.         Ext.QuickTip.superclass.hide.call(this);
  780.     }
  781. });/**
  782.  * @class Ext.QuickTips
  783.  * <p>Provides attractive and customizable tooltips for any element. The QuickTips
  784.  * singleton is used to configure and manage tooltips globally for multiple elements
  785.  * in a generic manner.  To create individual tooltips with maximum customizability,
  786.  * you should consider either {@link Ext.Tip} or {@link Ext.ToolTip}.</p>
  787.  * <p>Quicktips can be configured via tag attributes directly in markup, or by
  788.  * registering quick tips programmatically via the {@link #register} method.</p>
  789.  * <p>The singleton's instance of {@link Ext.QuickTip} is available via
  790.  * {@link #getQuickTip}, and supports all the methods, and all the all the
  791.  * configuration properties of Ext.QuickTip. These settings will apply to all
  792.  * tooltips shown by the singleton.</p>
  793.  * <p>Below is the summary of the configuration properties which can be used.
  794.  * For detailed descriptions see {@link #getQuickTip}</p>
  795.  * <p><b>QuickTips singleton configs (all are optional)</b></p>
  796.  * <div class="mdetail-params"><ul><li>dismissDelay</li>
  797.  * <li>hideDelay</li>
  798.  * <li>maxWidth</li>
  799.  * <li>minWidth</li>
  800.  * <li>showDelay</li>
  801.  * <li>trackMouse</li></ul></div>
  802.  * <p><b>Target element configs (optional unless otherwise noted)</b></p>
  803.  * <div class="mdetail-params"><ul><li>autoHide</li>
  804.  * <li>cls</li>
  805.  * <li>dismissDelay (overrides singleton value)</li>
  806.  * <li>target (required)</li>
  807.  * <li>text (required)</li>
  808.  * <li>title</li>
  809.  * <li>width</li></ul></div>
  810.  * <p>Here is an example showing how some of these config options could be used:</p>
  811.  * <pre><code>
  812. // Init the singleton.  Any tag-based quick tips will start working.
  813. Ext.QuickTips.init();
  814. // Apply a set of config properties to the singleton
  815. Ext.apply(Ext.QuickTips.getQuickTip(), {
  816.     maxWidth: 200,
  817.     minWidth: 100,
  818.     showDelay: 50,
  819.     trackMouse: true
  820. });
  821. // Manually register a quick tip for a specific element
  822. Ext.QuickTips.register({
  823.     target: 'my-div',
  824.     title: 'My Tooltip',
  825.     text: 'This tooltip was added in code',
  826.     width: 100,
  827.     dismissDelay: 20
  828. });
  829. </code></pre>
  830.  * <p>To register a quick tip in markup, you simply add one or more of the valid QuickTip attributes prefixed with
  831.  * the <b>ext:</b> namespace.  The HTML element itself is automatically set as the quick tip target. Here is the summary
  832.  * of supported attributes (optional unless otherwise noted):</p>
  833.  * <ul><li><b>hide</b>: Specifying "user" is equivalent to setting autoHide = false.  Any other value will be the
  834.  * same as autoHide = true.</li>
  835.  * <li><b>qclass</b>: A CSS class to be applied to the quick tip (equivalent to the 'cls' target element config).</li>
  836.  * <li><b>qtip (required)</b>: The quick tip text (equivalent to the 'text' target element config).</li>
  837.  * <li><b>qtitle</b>: The quick tip title (equivalent to the 'title' target element config).</li>
  838.  * <li><b>qwidth</b>: The quick tip width (equivalent to the 'width' target element config).</li></ul>
  839.  * <p>Here is an example of configuring an HTML element to display a tooltip from markup:</p>
  840.  * <pre><code>
  841. // Add a quick tip to an HTML button
  842. &lt;input type="button" value="OK" ext:qtitle="OK Button" ext:qwidth="100"
  843.      ext:qtip="This is a quick tip from markup!">&lt;/input>
  844. </code></pre>
  845.  * @singleton
  846.  */
  847. Ext.QuickTips = function(){
  848.     var tip, locks = [];
  849.     return {
  850.         /**
  851.          * Initialize the global QuickTips instance and prepare any quick tips.
  852.          * @param {Boolean} autoRender True to render the QuickTips container immediately to preload images. (Defaults to true) 
  853.          */
  854.         init : function(autoRender){
  855.             if(!tip){
  856.                 if(!Ext.isReady){
  857.                     Ext.onReady(function(){
  858.                         Ext.QuickTips.init(autoRender);
  859.                     });
  860.                     return;
  861.                 }
  862.                 tip = new Ext.QuickTip({elements:'header,body'});
  863.                 if(autoRender !== false){
  864.                     tip.render(Ext.getBody());
  865.                 }
  866.             }
  867.         },
  868.         /**
  869.          * Enable quick tips globally.
  870.          */
  871.         enable : function(){
  872.             if(tip){
  873.                 locks.pop();
  874.                 if(locks.length < 1){
  875.                     tip.enable();
  876.                 }
  877.             }
  878.         },
  879.         /**
  880.          * Disable quick tips globally.
  881.          */
  882.         disable : function(){
  883.             if(tip){
  884.                 tip.disable();
  885.             }
  886.             locks.push(1);
  887.         },
  888.         /**
  889.          * Returns true if quick tips are enabled, else false.
  890.          * @return {Boolean}
  891.          */
  892.         isEnabled : function(){
  893.             return tip !== undefined && !tip.disabled;
  894.         },
  895.         /**
  896.          * Gets the global QuickTips instance.
  897.          */
  898.         getQuickTip : function(){
  899.             return tip;
  900.         },
  901.         /**
  902.          * Configures a new quick tip instance and assigns it to a target element.  See
  903.          * {@link Ext.QuickTip#register} for details.
  904.          * @param {Object} config The config object
  905.          */
  906.         register : function(){
  907.             tip.register.apply(tip, arguments);
  908.         },
  909.         /**
  910.          * Removes any registered quick tip from the target element and destroys it.
  911.          * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
  912.          */
  913.         unregister : function(){
  914.             tip.unregister.apply(tip, arguments);
  915.         },
  916.         /**
  917.          * Alias of {@link #register}.
  918.          * @param {Object} config The config object
  919.          */
  920.         tips :function(){
  921.             tip.register.apply(tip, arguments);
  922.         }
  923.     }
  924. }();