pkg-buttons-debug.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:37k
源码类别:

JavaScript

开发平台:

JavaScript

  1. /*!  * Ext JS Library 3.1.0  * Copyright(c) 2006-2009 Ext JS, LLC  * licensing@extjs.com  * http://www.extjs.com/license  */ /**
  2.  * @class Ext.Button
  3.  * @extends Ext.BoxComponent
  4.  * Simple Button class
  5.  * @cfg {String} text The button text to be used as innerHTML (html tags are accepted)
  6.  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
  7.  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:'x-btn-text-icon')
  8.  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event).
  9.  * The handler is passed the following parameters:<div class="mdetail-params"><ul>
  10.  * <li><code>b</code> : Button<div class="sub-desc">This Button.</div></li>
  11.  * <li><code>e</code> : EventObject<div class="sub-desc">The click event.</div></li>
  12.  * </ul></div>
  13.  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width).
  14.  * See also {@link Ext.Panel}.<tt>{@link Ext.Panel#minButtonWidth minButtonWidth}</tt>.
  15.  * @cfg {String/Object} tooltip The tooltip for the button - can be a string to be used as innerHTML (html tags are accepted) or QuickTips config object
  16.  * @cfg {Boolean} hidden True to start hidden (defaults to false)
  17.  * @cfg {Boolean} disabled True to start disabled (defaults to false)
  18.  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
  19.  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed)
  20.  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
  21.  * a {@link Ext.util.ClickRepeater ClickRepeater} config object (defaults to false).
  22.  * @constructor
  23.  * Create a new button
  24.  * @param {Object} config The config object
  25.  * @xtype button
  26.  */
  27. Ext.Button = Ext.extend(Ext.BoxComponent, {
  28.     /**
  29.      * Read-only. True if this button is hidden
  30.      * @type Boolean
  31.      */
  32.     hidden : false,
  33.     /**
  34.      * Read-only. True if this button is disabled
  35.      * @type Boolean
  36.      */
  37.     disabled : false,
  38.     /**
  39.      * Read-only. True if this button is pressed (only if enableToggle = true)
  40.      * @type Boolean
  41.      */
  42.     pressed : false,
  43.     /**
  44.      * @cfg {Number} tabIndex Set a DOM tabIndex for this button (defaults to undefined)
  45.      */
  46.     /**
  47.      * @cfg {Boolean} allowDepress
  48.      * False to not allow a pressed Button to be depressed (defaults to undefined). Only valid when {@link #enableToggle} is true.
  49.      */
  50.     /**
  51.      * @cfg {Boolean} enableToggle
  52.      * True to enable pressed/not pressed toggling (defaults to false)
  53.      */
  54.     enableToggle : false,
  55.     /**
  56.      * @cfg {Function} toggleHandler
  57.      * Function called when a Button with {@link #enableToggle} set to true is clicked. Two arguments are passed:<ul class="mdetail-params">
  58.      * <li><b>button</b> : Ext.Button<div class="sub-desc">this Button object</div></li>
  59.      * <li><b>state</b> : Boolean<div class="sub-desc">The next state of the Button, true means pressed.</div></li>
  60.      * </ul>
  61.      */
  62.     /**
  63.      * @cfg {Mixed} menu
  64.      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
  65.      */
  66.     /**
  67.      * @cfg {String} menuAlign
  68.      * The position to align the menu to (see {@link Ext.Element#alignTo} for more details, defaults to 'tl-bl?').
  69.      */
  70.     menuAlign : 'tl-bl?',
  71.     /**
  72.      * @cfg {String} overflowText If used in a {@link Ext.Toolbar Toolbar}, the
  73.      * text to be used if this item is shown in the overflow menu. See also
  74.      * {@link Ext.Toolbar.Item}.<code>{@link Ext.Toolbar.Item#overflowText overflowText}</code>.
  75.      */
  76.     /**
  77.      * @cfg {String} iconCls
  78.      * A css class which sets a background image to be used as the icon for this button
  79.      */
  80.     /**
  81.      * @cfg {String} type
  82.      * submit, reset or button - defaults to 'button'
  83.      */
  84.     type : 'button',
  85.     // private
  86.     menuClassTarget : 'tr:nth(2)',
  87.     /**
  88.      * @cfg {String} clickEvent
  89.      * The DOM event that will fire the handler of the button. This can be any valid event name (dblclick, contextmenu).
  90.      * Defaults to <tt>'click'</tt>.
  91.      */
  92.     clickEvent : 'click',
  93.     /**
  94.      * @cfg {Boolean} handleMouseEvents
  95.      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
  96.      */
  97.     handleMouseEvents : true,
  98.     /**
  99.      * @cfg {String} tooltipType
  100.      * The type of tooltip to use. Either 'qtip' (default) for QuickTips or 'title' for title attribute.
  101.      */
  102.     tooltipType : 'qtip',
  103.     /**
  104.      * @cfg {String} buttonSelector
  105.      * <p>(Optional) A {@link Ext.DomQuery DomQuery} selector which is used to extract the active, clickable element from the
  106.      * DOM structure created.</p>
  107.      * <p>When a custom {@link #template} is used, you  must ensure that this selector results in the selection of
  108.      * a focussable element.</p>
  109.      * <p>Defaults to <b><tt>'button:first-child'</tt></b>.</p>
  110.      */
  111.     buttonSelector : 'button:first-child',
  112.     /**
  113.      * @cfg {String} scale
  114.      * <p>(Optional) The size of the Button. Three values are allowed:</p>
  115.      * <ul class="mdetail-params">
  116.      * <li>'small'<div class="sub-desc">Results in the button element being 16px high.</div></li>
  117.      * <li>'medium'<div class="sub-desc">Results in the button element being 24px high.</div></li>
  118.      * <li>'large'<div class="sub-desc">Results in the button element being 32px high.</div></li>
  119.      * </ul>
  120.      * <p>Defaults to <b><tt>'small'</tt></b>.</p>
  121.      */
  122.     scale : 'small',
  123.     /**
  124.      * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
  125.      * <code>{@link #handler}</code> and <code>{@link #toggleHandler}</code> is
  126.      * executed. Defaults to this Button.
  127.      */
  128.     /**
  129.      * @cfg {String} iconAlign
  130.      * <p>(Optional) The side of the Button box to render the icon. Four values are allowed:</p>
  131.      * <ul class="mdetail-params">
  132.      * <li>'top'<div class="sub-desc"></div></li>
  133.      * <li>'right'<div class="sub-desc"></div></li>
  134.      * <li>'bottom'<div class="sub-desc"></div></li>
  135.      * <li>'left'<div class="sub-desc"></div></li>
  136.      * </ul>
  137.      * <p>Defaults to <b><tt>'left'</tt></b>.</p>
  138.      */
  139.     iconAlign : 'left',
  140.     /**
  141.      * @cfg {String} arrowAlign
  142.      * <p>(Optional) The side of the Button box to render the arrow if the button has an associated {@link #menu}.
  143.      * Two values are allowed:</p>
  144.      * <ul class="mdetail-params">
  145.      * <li>'right'<div class="sub-desc"></div></li>
  146.      * <li>'bottom'<div class="sub-desc"></div></li>
  147.      * </ul>
  148.      * <p>Defaults to <b><tt>'right'</tt></b>.</p>
  149.      */
  150.     arrowAlign : 'right',
  151.     /**
  152.      * @cfg {Ext.Template} template (Optional)
  153.      * <p>A {@link Ext.Template Template} used to create the Button's DOM structure.</p>
  154.      * Instances, or subclasses which need a different DOM structure may provide a different
  155.      * template layout in conjunction with an implementation of {@link #getTemplateArgs}.
  156.      * @type Ext.Template
  157.      * @property template
  158.      */
  159.     /**
  160.      * @cfg {String} cls
  161.      * A CSS class string to apply to the button's main element.
  162.      */
  163.     /**
  164.      * @property menu
  165.      * @type Menu
  166.      * The {@link Ext.menu.Menu Menu} object associated with this Button when configured with the {@link #menu} config option.
  167.      */
  168.     initComponent : function(){
  169.         Ext.Button.superclass.initComponent.call(this);
  170.         this.addEvents(
  171.             /**
  172.              * @event click
  173.              * Fires when this button is clicked
  174.              * @param {Button} this
  175.              * @param {EventObject} e The click event
  176.              */
  177.             'click',
  178.             /**
  179.              * @event toggle
  180.              * Fires when the 'pressed' state of this button changes (only if enableToggle = true)
  181.              * @param {Button} this
  182.              * @param {Boolean} pressed
  183.              */
  184.             'toggle',
  185.             /**
  186.              * @event mouseover
  187.              * Fires when the mouse hovers over the button
  188.              * @param {Button} this
  189.              * @param {Event} e The event object
  190.              */
  191.             'mouseover',
  192.             /**
  193.              * @event mouseout
  194.              * Fires when the mouse exits the button
  195.              * @param {Button} this
  196.              * @param {Event} e The event object
  197.              */
  198.             'mouseout',
  199.             /**
  200.              * @event menushow
  201.              * If this button has a menu, this event fires when it is shown
  202.              * @param {Button} this
  203.              * @param {Menu} menu
  204.              */
  205.             'menushow',
  206.             /**
  207.              * @event menuhide
  208.              * If this button has a menu, this event fires when it is hidden
  209.              * @param {Button} this
  210.              * @param {Menu} menu
  211.              */
  212.             'menuhide',
  213.             /**
  214.              * @event menutriggerover
  215.              * If this button has a menu, this event fires when the mouse enters the menu triggering element
  216.              * @param {Button} this
  217.              * @param {Menu} menu
  218.              * @param {EventObject} e
  219.              */
  220.             'menutriggerover',
  221.             /**
  222.              * @event menutriggerout
  223.              * If this button has a menu, this event fires when the mouse leaves the menu triggering element
  224.              * @param {Button} this
  225.              * @param {Menu} menu
  226.              * @param {EventObject} e
  227.              */
  228.             'menutriggerout'
  229.         );
  230.         if(this.menu){
  231.             this.menu = Ext.menu.MenuMgr.get(this.menu);
  232.         }
  233.         if(Ext.isString(this.toggleGroup)){
  234.             this.enableToggle = true;
  235.         }
  236.     },
  237. /**
  238.   * <p>This method returns an Array which provides substitution parameters for the {@link #template Template} used
  239.   * to create this Button's DOM structure.</p>
  240.   * <p>Instances or subclasses which use a different Template to create a different DOM structure may need to provide their
  241.   * own implementation of this method.</p>
  242.   * <p>The default implementation which provides data for the default {@link #template} returns an Array containing the
  243.   * following items:</p><div class="mdetail-params"><ul>
  244.   * <li>The &lt;button&gt;'s {@link #type}</li>
  245.   * <li>A CSS class name applied to the Button's main &lt;tbody&gt; element which determines the button's scale and icon alignment.</li>
  246.   * <li>A CSS class to determine the presence and position of an arrow icon. (<code>'x-btn-arrow'</code> or <code>'x-btn-arrow-bottom'</code> or <code>''</code>)</li>
  247.   * <li>The {@link #cls} CSS class name applied to the button's wrapping &lt;table&gt; element.</li>
  248.   * <li>The Component id which is applied to the button's wrapping &lt;table&gt; element.</li>
  249.   * </ul></div>
  250.   * @return {Array} Substitution data for a Template.
  251.  */
  252.     getTemplateArgs : function(){
  253.         return [this.type, 'x-btn-' + this.scale + ' x-btn-icon-' + this.scale + '-' + this.iconAlign, this.getMenuClass(), this.cls, this.id];
  254.     },
  255.     // private
  256.     setButtonClass : function(){
  257.         if(this.useSetClass){
  258.             if(!Ext.isEmpty(this.oldCls)){
  259.                 this.el.removeClass([this.oldCls, 'x-btn-pressed']);
  260.             }
  261.             this.oldCls = (this.iconCls || this.icon) ? (this.text ? ' x-btn-text-icon' : ' x-btn-icon') : ' x-btn-noicon';
  262.             this.el.addClass([this.oldCls, this.pressed ? 'x-btn-pressed' : null]);
  263.         }
  264.     },
  265.     // protected
  266.     getMenuClass : function(){
  267.         return this.menu ? (this.arrowAlign != 'bottom' ? 'x-btn-arrow' : 'x-btn-arrow-bottom') : '';
  268.     },
  269.     // private
  270.     onRender : function(ct, position){
  271.         if(!this.template){
  272.             if(!Ext.Button.buttonTemplate){
  273.                 // hideous table template
  274.                 Ext.Button.buttonTemplate = new Ext.Template(
  275.                     '<table id="{4}" cellspacing="0" class="x-btn {3}"><tbody class="{1}">',
  276.                     '<tr><td class="x-btn-tl"><i>&#160;</i></td><td class="x-btn-tc"></td><td class="x-btn-tr"><i>&#160;</i></td></tr>',
  277.                     '<tr><td class="x-btn-ml"><i>&#160;</i></td><td class="x-btn-mc"><em class="{2}" unselectable="on"><button type="{0}"></button></em></td><td class="x-btn-mr"><i>&#160;</i></td></tr>',
  278.                     '<tr><td class="x-btn-bl"><i>&#160;</i></td><td class="x-btn-bc"></td><td class="x-btn-br"><i>&#160;</i></td></tr>',
  279.                     '</tbody></table>');
  280.                 Ext.Button.buttonTemplate.compile();
  281.             }
  282.             this.template = Ext.Button.buttonTemplate;
  283.         }
  284.         var btn, targs = this.getTemplateArgs();
  285.         if(position){
  286.             btn = this.template.insertBefore(position, targs, true);
  287.         }else{
  288.             btn = this.template.append(ct, targs, true);
  289.         }
  290.         /**
  291.          * An {@link Ext.Element Element} encapsulating the Button's clickable element. By default,
  292.          * this references a <tt>&lt;button&gt;</tt> element. Read only.
  293.          * @type Ext.Element
  294.          * @property btnEl
  295.          */
  296.         this.btnEl = btn.child(this.buttonSelector);
  297.         this.mon(this.btnEl, {
  298.             scope: this,
  299.             focus: this.onFocus,
  300.             blur: this.onBlur
  301.         });
  302.         this.initButtonEl(btn, this.btnEl);
  303.         Ext.ButtonToggleMgr.register(this);
  304.     },
  305.     // private
  306.     initButtonEl : function(btn, btnEl){
  307.         this.el = btn;
  308.         this.setIcon(this.icon);
  309.         this.setText(this.text);
  310.         this.setIconClass(this.iconCls);
  311.         if(Ext.isDefined(this.tabIndex)){
  312.             btnEl.dom.tabIndex = this.tabIndex;
  313.         }
  314.         if(this.tooltip){
  315.             this.setTooltip(this.tooltip, true);
  316.         }
  317.         if(this.handleMouseEvents){
  318.             this.mon(btn, {
  319.                 scope: this,
  320.                 mouseover: this.onMouseOver,
  321.                 mousedown: this.onMouseDown
  322.             });
  323.             // new functionality for monitoring on the document level
  324.             //this.mon(btn, 'mouseout', this.onMouseOut, this);
  325.         }
  326.         if(this.menu){
  327.             this.mon(this.menu, {
  328.                 scope: this,
  329.                 show: this.onMenuShow,
  330.                 hide: this.onMenuHide
  331.             });
  332.         }
  333.         if(this.repeat){
  334.             var repeater = new Ext.util.ClickRepeater(btn, Ext.isObject(this.repeat) ? this.repeat : {});
  335.             this.mon(repeater, 'click', this.onClick, this);
  336.         }
  337.         this.mon(btn, this.clickEvent, this.onClick, this);
  338.     },
  339.     // private
  340.     afterRender : function(){
  341.         Ext.Button.superclass.afterRender.call(this);
  342.         this.useSetClass = true;
  343.         this.setButtonClass();
  344.         this.doc = Ext.getDoc();
  345.         this.doAutoWidth();
  346.     },
  347.     /**
  348.      * Sets the CSS class that provides a background image to use as the button's icon.  This method also changes
  349.      * the value of the {@link iconCls} config internally.
  350.      * @param {String} cls The CSS class providing the icon image
  351.      * @return {Ext.Button} this
  352.      */
  353.     setIconClass : function(cls){
  354.         this.iconCls = cls;
  355.         if(this.el){
  356.             this.btnEl.dom.className = '';
  357.             this.btnEl.addClass(['x-btn-text', cls || '']);
  358.             this.setButtonClass();
  359.         }
  360.         return this;
  361.     },
  362.     /**
  363.      * Sets the tooltip for this Button.
  364.      * @param {String/Object} tooltip. This may be:<div class="mdesc-details"><ul>
  365.      * <li><b>String</b> : A string to be used as innerHTML (html tags are accepted) to show in a tooltip</li>
  366.      * <li><b>Object</b> : A configuration object for {@link Ext.QuickTips#register}.</li>
  367.      * </ul></div>
  368.      * @return {Ext.Button} this
  369.      */
  370.     setTooltip : function(tooltip, /* private */ initial){
  371.         if(this.rendered){
  372.             if(!initial){
  373.                 this.clearTip();
  374.             }
  375.             if(Ext.isObject(tooltip)){
  376.                 Ext.QuickTips.register(Ext.apply({
  377.                       target: this.btnEl.id
  378.                 }, tooltip));
  379.                 this.tooltip = tooltip;
  380.             }else{
  381.                 this.btnEl.dom[this.tooltipType] = tooltip;
  382.             }
  383.         }else{
  384.             this.tooltip = tooltip;
  385.         }
  386.         return this;
  387.     },
  388.     // private
  389.     clearTip : function(){
  390.         if(Ext.isObject(this.tooltip)){
  391.             Ext.QuickTips.unregister(this.btnEl);
  392.         }
  393.     },
  394.     // private
  395.     beforeDestroy : function(){
  396.         if(this.rendered){
  397.             this.clearTip();
  398.         }
  399.         if(this.menu && this.menu.autoDestroy) {
  400.             Ext.destroy(this.menu);
  401.         }
  402.         Ext.destroy(this.repeater);
  403.     },
  404.     // private
  405.     onDestroy : function(){
  406.         if(this.rendered){
  407.             this.doc.un('mouseover', this.monitorMouseOver, this);
  408.             this.doc.un('mouseup', this.onMouseUp, this);
  409.             delete this.doc;
  410.             delete this.btnEl;
  411.             Ext.ButtonToggleMgr.unregister(this);
  412.         }
  413.     },
  414.     // private
  415.     doAutoWidth : function(){
  416.         if(this.el && this.text && this.width === undefined){
  417.             this.el.setWidth('auto');
  418.             if(Ext.isIE7 && Ext.isStrict){
  419.                 var ib = this.btnEl;
  420.                 if(ib && ib.getWidth() > 20){
  421.                     ib.clip();
  422.                     ib.setWidth(Ext.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
  423.                 }
  424.             }
  425.             if(this.minWidth){
  426.                 if(this.el.getWidth() < this.minWidth){
  427.                     this.el.setWidth(this.minWidth);
  428.                 }
  429.             }
  430.         }
  431.     },
  432.     /**
  433.      * Assigns this Button's click handler
  434.      * @param {Function} handler The function to call when the button is clicked
  435.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
  436.      * Defaults to this Button.
  437.      * @return {Ext.Button} this
  438.      */
  439.     setHandler : function(handler, scope){
  440.         this.handler = handler;
  441.         this.scope = scope;
  442.         return this;
  443.     },
  444.     /**
  445.      * Sets this Button's text
  446.      * @param {String} text The button text
  447.      * @return {Ext.Button} this
  448.      */
  449.     setText : function(text){
  450.         this.text = text;
  451.         if(this.el){
  452.             this.btnEl.update(text || '&#160;');
  453.             this.setButtonClass();
  454.         }
  455.         this.doAutoWidth();
  456.         return this;
  457.     },
  458.     /**
  459.      * Sets the background image (inline style) of the button.  This method also changes
  460.      * the value of the {@link icon} config internally.
  461.      * @param {String} icon The path to an image to display in the button
  462.      * @return {Ext.Button} this
  463.      */
  464.     setIcon : function(icon){
  465.         this.icon = icon;
  466.         if(this.el){
  467.             this.btnEl.setStyle('background-image', icon ? 'url(' + icon + ')' : '');
  468.             this.setButtonClass();
  469.         }
  470.         return this;
  471.     },
  472.     /**
  473.      * Gets the text for this Button
  474.      * @return {String} The button text
  475.      */
  476.     getText : function(){
  477.         return this.text;
  478.     },
  479.     /**
  480.      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
  481.      * @param {Boolean} state (optional) Force a particular state
  482.      * @param {Boolean} supressEvent (optional) True to stop events being fired when calling this method.
  483.      * @return {Ext.Button} this
  484.      */
  485.     toggle : function(state, suppressEvent){
  486.         state = state === undefined ? !this.pressed : !!state;
  487.         if(state != this.pressed){
  488.             if(this.rendered){
  489.                 this.el[state ? 'addClass' : 'removeClass']('x-btn-pressed');
  490.             }
  491.             this.pressed = state;
  492.             if(!suppressEvent){
  493.                 this.fireEvent('toggle', this, state);
  494.                 if(this.toggleHandler){
  495.                     this.toggleHandler.call(this.scope || this, this, state);
  496.                 }
  497.             }
  498.         }
  499.         return this;
  500.     },
  501.     /**
  502.      * Focus the button
  503.      */
  504.     focus : function(){
  505.         this.btnEl.focus();
  506.     },
  507.     // private
  508.     onDisable : function(){
  509.         this.onDisableChange(true);
  510.     },
  511.     // private
  512.     onEnable : function(){
  513.         this.onDisableChange(false);
  514.     },
  515.     onDisableChange : function(disabled){
  516.         if(this.el){
  517.             if(!Ext.isIE6 || !this.text){
  518.                 this.el[disabled ? 'addClass' : 'removeClass'](this.disabledClass);
  519.             }
  520.             this.el.dom.disabled = disabled;
  521.         }
  522.         this.disabled = disabled;
  523.     },
  524.     /**
  525.      * Show this button's menu (if it has one)
  526.      */
  527.     showMenu : function(){
  528.         if(this.rendered && this.menu){
  529.             if(this.tooltip){
  530.                 Ext.QuickTips.getQuickTip().cancelShow(this.btnEl);
  531.             }
  532.             this.menu.show(this.el, this.menuAlign);
  533.         }
  534.         return this;
  535.     },
  536.     /**
  537.      * Hide this button's menu (if it has one)
  538.      */
  539.     hideMenu : function(){
  540.         if(this.menu){
  541.             this.menu.hide();
  542.         }
  543.         return this;
  544.     },
  545.     /**
  546.      * Returns true if the button has a menu and it is visible
  547.      * @return {Boolean}
  548.      */
  549.     hasVisibleMenu : function(){
  550.         return this.menu && this.menu.isVisible();
  551.     },
  552.     // private
  553.     onClick : function(e){
  554.         if(e){
  555.             e.preventDefault();
  556.         }
  557.         if(e.button !== 0){
  558.             return;
  559.         }
  560.         if(!this.disabled){
  561.             if(this.enableToggle && (this.allowDepress !== false || !this.pressed)){
  562.                 this.toggle();
  563.             }
  564.             if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){
  565.                 this.showMenu();
  566.             }
  567.             this.fireEvent('click', this, e);
  568.             if(this.handler){
  569.                 //this.el.removeClass('x-btn-over');
  570.                 this.handler.call(this.scope || this, this, e);
  571.             }
  572.         }
  573.     },
  574.     // private
  575.     isMenuTriggerOver : function(e, internal){
  576.         return this.menu && !internal;
  577.     },
  578.     // private
  579.     isMenuTriggerOut : function(e, internal){
  580.         return this.menu && !internal;
  581.     },
  582.     // private
  583.     onMouseOver : function(e){
  584.         if(!this.disabled){
  585.             var internal = e.within(this.el,  true);
  586.             if(!internal){
  587.                 this.el.addClass('x-btn-over');
  588.                 if(!this.monitoringMouseOver){
  589.                     this.doc.on('mouseover', this.monitorMouseOver, this);
  590.                     this.monitoringMouseOver = true;
  591.                 }
  592.                 this.fireEvent('mouseover', this, e);
  593.             }
  594.             if(this.isMenuTriggerOver(e, internal)){
  595.                 this.fireEvent('menutriggerover', this, this.menu, e);
  596.             }
  597.         }
  598.     },
  599.     // private
  600.     monitorMouseOver : function(e){
  601.         if(e.target != this.el.dom && !e.within(this.el)){
  602.             if(this.monitoringMouseOver){
  603.                 this.doc.un('mouseover', this.monitorMouseOver, this);
  604.                 this.monitoringMouseOver = false;
  605.             }
  606.             this.onMouseOut(e);
  607.         }
  608.     },
  609.     // private
  610.     onMouseOut : function(e){
  611.         var internal = e.within(this.el) && e.target != this.el.dom;
  612.         this.el.removeClass('x-btn-over');
  613.         this.fireEvent('mouseout', this, e);
  614.         if(this.isMenuTriggerOut(e, internal)){
  615.             this.fireEvent('menutriggerout', this, this.menu, e);
  616.         }
  617.     },
  618.     focus : function() {
  619.         this.btnEl.focus();
  620.     },
  621.     blur : function() {
  622.         this.btnEl.blur();
  623.     },
  624.     // private
  625.     onFocus : function(e){
  626.         if(!this.disabled){
  627.             this.el.addClass('x-btn-focus');
  628.         }
  629.     },
  630.     // private
  631.     onBlur : function(e){
  632.         this.el.removeClass('x-btn-focus');
  633.     },
  634.     // private
  635.     getClickEl : function(e, isUp){
  636.        return this.el;
  637.     },
  638.     // private
  639.     onMouseDown : function(e){
  640.         if(!this.disabled && e.button === 0){
  641.             this.getClickEl(e).addClass('x-btn-click');
  642.             this.doc.on('mouseup', this.onMouseUp, this);
  643.         }
  644.     },
  645.     // private
  646.     onMouseUp : function(e){
  647.         if(e.button === 0){
  648.             this.getClickEl(e, true).removeClass('x-btn-click');
  649.             this.doc.un('mouseup', this.onMouseUp, this);
  650.         }
  651.     },
  652.     // private
  653.     onMenuShow : function(e){
  654.         this.menu.ownerCt = this;
  655.         this.ignoreNextClick = 0;
  656.         this.el.addClass('x-btn-menu-active');
  657.         this.fireEvent('menushow', this, this.menu);
  658.     },
  659.     // private
  660.     onMenuHide : function(e){
  661.         this.el.removeClass('x-btn-menu-active');
  662.         this.ignoreNextClick = this.restoreClick.defer(250, this);
  663.         this.fireEvent('menuhide', this, this.menu);
  664.         delete this.menu.ownerCt;
  665.     },
  666.     // private
  667.     restoreClick : function(){
  668.         this.ignoreNextClick = 0;
  669.     }
  670.     /**
  671.      * @cfg {String} autoEl @hide
  672.      */
  673. });
  674. Ext.reg('button', Ext.Button);
  675. // Private utility class used by Button
  676. Ext.ButtonToggleMgr = function(){
  677.    var groups = {};
  678.    function toggleGroup(btn, state){
  679.        if(state){
  680.            var g = groups[btn.toggleGroup];
  681.            for(var i = 0, l = g.length; i < l; i++){
  682.                if(g[i] != btn){
  683.                    g[i].toggle(false);
  684.                }
  685.            }
  686.        }
  687.    }
  688.    return {
  689.        register : function(btn){
  690.            if(!btn.toggleGroup){
  691.                return;
  692.            }
  693.            var g = groups[btn.toggleGroup];
  694.            if(!g){
  695.                g = groups[btn.toggleGroup] = [];
  696.            }
  697.            g.push(btn);
  698.            btn.on('toggle', toggleGroup);
  699.        },
  700.        unregister : function(btn){
  701.            if(!btn.toggleGroup){
  702.                return;
  703.            }
  704.            var g = groups[btn.toggleGroup];
  705.            if(g){
  706.                g.remove(btn);
  707.                btn.un('toggle', toggleGroup);
  708.            }
  709.        },
  710.        /**
  711.         * Gets the pressed button in the passed group or null
  712.         * @param {String} group
  713.         * @return Button
  714.         */
  715.        getPressed : function(group){
  716.            var g = groups[group];
  717.            if(g){
  718.                for(var i = 0, len = g.length; i < len; i++){
  719.                    if(g[i].pressed === true){
  720.                        return g[i];
  721.                    }
  722.                }
  723.            }
  724.            return null;
  725.        }
  726.    };
  727. }();
  728. /**
  729.  * @class Ext.SplitButton
  730.  * @extends Ext.Button
  731.  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
  732.  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
  733.  * options to the primary button action, but any custom handler can provide the arrowclick implementation.  Example usage:
  734.  * <pre><code>
  735. // display a dropdown menu:
  736. new Ext.SplitButton({
  737. renderTo: 'button-ct', // the container id
  738.     text: 'Options',
  739.     handler: optionsHandler, // handle a click on the button itself
  740.     menu: new Ext.menu.Menu({
  741.         items: [
  742.          // these items will render as dropdown menu items when the arrow is clicked:
  743.         {text: 'Item 1', handler: item1Handler},
  744.         {text: 'Item 2', handler: item2Handler}
  745.         ]
  746.     })
  747. });
  748. // Instead of showing a menu, you provide any type of custom
  749. // functionality you want when the dropdown arrow is clicked:
  750. new Ext.SplitButton({
  751. renderTo: 'button-ct',
  752.     text: 'Options',
  753.     handler: optionsHandler,
  754.     arrowHandler: myCustomHandler
  755. });
  756. </code></pre>
  757.  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
  758.  * @cfg {String} arrowTooltip The title attribute of the arrow
  759.  * @constructor
  760.  * Create a new menu button
  761.  * @param {Object} config The config object
  762.  * @xtype splitbutton
  763.  */
  764. Ext.SplitButton = Ext.extend(Ext.Button, {
  765. // private
  766.     arrowSelector : 'em',
  767.     split: true,
  768.     // private
  769.     initComponent : function(){
  770.         Ext.SplitButton.superclass.initComponent.call(this);
  771.         /**
  772.          * @event arrowclick
  773.          * Fires when this button's arrow is clicked
  774.          * @param {MenuButton} this
  775.          * @param {EventObject} e The click event
  776.          */
  777.         this.addEvents("arrowclick");
  778.     },
  779.     // private
  780.     onRender : function(){
  781.         Ext.SplitButton.superclass.onRender.apply(this, arguments);
  782.         if(this.arrowTooltip){
  783.             this.el.child(this.arrowSelector).dom[this.tooltipType] = this.arrowTooltip;
  784.         }
  785.     },
  786.     /**
  787.      * Sets this button's arrow click handler.
  788.      * @param {Function} handler The function to call when the arrow is clicked
  789.      * @param {Object} scope (optional) Scope for the function passed above
  790.      */
  791.     setArrowHandler : function(handler, scope){
  792.         this.arrowHandler = handler;
  793.         this.scope = scope;
  794.     },
  795.     getMenuClass : function(){
  796.         return 'x-btn-split' + (this.arrowAlign == 'bottom' ? '-bottom' : '');
  797.     },
  798.     isClickOnArrow : function(e){
  799. if (this.arrowAlign != 'bottom') {
  800.     var visBtn = this.el.child('em.x-btn-split');
  801.     var right = visBtn.getRegion().right - visBtn.getPadding('r');
  802.     return e.getPageX() > right;
  803. } else {
  804.     return e.getPageY() > this.btnEl.getRegion().bottom;
  805. }
  806.     },
  807.     // private
  808.     onClick : function(e, t){
  809.         e.preventDefault();
  810.         if(!this.disabled){
  811.             if(this.isClickOnArrow(e)){
  812.                 if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){
  813.                     this.showMenu();
  814.                 }
  815.                 this.fireEvent("arrowclick", this, e);
  816.                 if(this.arrowHandler){
  817.                     this.arrowHandler.call(this.scope || this, this, e);
  818.                 }
  819.             }else{
  820.                 if(this.enableToggle){
  821.                     this.toggle();
  822.                 }
  823.                 this.fireEvent("click", this, e);
  824.                 if(this.handler){
  825.                     this.handler.call(this.scope || this, this, e);
  826.                 }
  827.             }
  828.         }
  829.     },
  830.     // private
  831.     isMenuTriggerOver : function(e){
  832.         return this.menu && e.target.tagName == this.arrowSelector;
  833.     },
  834.     // private
  835.     isMenuTriggerOut : function(e, internal){
  836.         return this.menu && e.target.tagName != this.arrowSelector;
  837.     }
  838. });
  839. Ext.reg('splitbutton', Ext.SplitButton);/**
  840.  * @class Ext.CycleButton
  841.  * @extends Ext.SplitButton
  842.  * A specialized SplitButton that contains a menu of {@link Ext.menu.CheckItem} elements.  The button automatically
  843.  * cycles through each menu item on click, raising the button's {@link #change} event (or calling the button's
  844.  * {@link #changeHandler} function, if supplied) for the active menu item. Clicking on the arrow section of the
  845.  * button displays the dropdown menu just like a normal SplitButton.  Example usage:
  846.  * <pre><code>
  847. var btn = new Ext.CycleButton({
  848.     showText: true,
  849.     prependText: 'View as ',
  850.     items: [{
  851.         text:'text only',
  852.         iconCls:'view-text',
  853.         checked:true
  854.     },{
  855.         text:'HTML',
  856.         iconCls:'view-html'
  857.     }],
  858.     changeHandler:function(btn, item){
  859.         Ext.Msg.alert('Change View', item.text);
  860.     }
  861. });
  862. </code></pre>
  863.  * @constructor
  864.  * Create a new split button
  865.  * @param {Object} config The config object
  866.  * @xtype cycle
  867.  */
  868. Ext.CycleButton = Ext.extend(Ext.SplitButton, {
  869.     /**
  870.      * @cfg {Array} items An array of {@link Ext.menu.CheckItem} <b>config</b> objects to be used when creating the
  871.      * button's menu items (e.g., {text:'Foo', iconCls:'foo-icon'})
  872.      */
  873.     /**
  874.      * @cfg {Boolean} showText True to display the active item's text as the button text (defaults to false)
  875.      */
  876.     /**
  877.      * @cfg {String} prependText A static string to prepend before the active item's text when displayed as the
  878.      * button's text (only applies when showText = true, defaults to '')
  879.      */
  880.     /**
  881.      * @cfg {Function} changeHandler A callback function that will be invoked each time the active menu
  882.      * item in the button's menu has changed.  If this callback is not supplied, the SplitButton will instead
  883.      * fire the {@link #change} event on active item change.  The changeHandler function will be called with the
  884.      * following argument list: (SplitButton this, Ext.menu.CheckItem item)
  885.      */
  886.     /**
  887.      * @cfg {String} forceIcon A css class which sets an image to be used as the static icon for this button.  This
  888.      * icon will always be displayed regardless of which item is selected in the dropdown list.  This overrides the 
  889.      * default behavior of changing the button's icon to match the selected item's icon on change.
  890.      */
  891.     /**
  892.      * @property menu
  893.      * @type Menu
  894.      * The {@link Ext.menu.Menu Menu} object used to display the {@link Ext.menu.CheckItem CheckItems} representing the available choices.
  895.      */
  896.     // private
  897.     getItemText : function(item){
  898.         if(item && this.showText === true){
  899.             var text = '';
  900.             if(this.prependText){
  901.                 text += this.prependText;
  902.             }
  903.             text += item.text;
  904.             return text;
  905.         }
  906.         return undefined;
  907.     },
  908.     /**
  909.      * Sets the button's active menu item.
  910.      * @param {Ext.menu.CheckItem} item The item to activate
  911.      * @param {Boolean} suppressEvent True to prevent the button's change event from firing (defaults to false)
  912.      */
  913.     setActiveItem : function(item, suppressEvent){
  914.         if(!Ext.isObject(item)){
  915.             item = this.menu.getComponent(item);
  916.         }
  917.         if(item){
  918.             if(!this.rendered){
  919.                 this.text = this.getItemText(item);
  920.                 this.iconCls = item.iconCls;
  921.             }else{
  922.                 var t = this.getItemText(item);
  923.                 if(t){
  924.                     this.setText(t);
  925.                 }
  926.                 this.setIconClass(item.iconCls);
  927.             }
  928.             this.activeItem = item;
  929.             if(!item.checked){
  930.                 item.setChecked(true, true);
  931.             }
  932.             if(this.forceIcon){
  933.                 this.setIconClass(this.forceIcon);
  934.             }
  935.             if(!suppressEvent){
  936.                 this.fireEvent('change', this, item);
  937.             }
  938.         }
  939.     },
  940.     /**
  941.      * Gets the currently active menu item.
  942.      * @return {Ext.menu.CheckItem} The active item
  943.      */
  944.     getActiveItem : function(){
  945.         return this.activeItem;
  946.     },
  947.     // private
  948.     initComponent : function(){
  949.         this.addEvents(
  950.             /**
  951.              * @event change
  952.              * Fires after the button's active menu item has changed.  Note that if a {@link #changeHandler} function
  953.              * is set on this CycleButton, it will be called instead on active item change and this change event will
  954.              * not be fired.
  955.              * @param {Ext.CycleButton} this
  956.              * @param {Ext.menu.CheckItem} item The menu item that was selected
  957.              */
  958.             "change"
  959.         );
  960.         if(this.changeHandler){
  961.             this.on('change', this.changeHandler, this.scope||this);
  962.             delete this.changeHandler;
  963.         }
  964.         this.itemCount = this.items.length;
  965.         this.menu = {cls:'x-cycle-menu', items:[]};
  966.         var checked;
  967.         Ext.each(this.items, function(item, i){
  968.             Ext.apply(item, {
  969.                 group: item.group || this.id,
  970.                 itemIndex: i,
  971.                 checkHandler: this.checkHandler,
  972.                 scope: this,
  973.                 checked: item.checked || false
  974.             });
  975.             this.menu.items.push(item);
  976.             if(item.checked){
  977.                 checked = item;
  978.             }
  979.         }, this);
  980.         this.setActiveItem(checked, true);
  981.         Ext.CycleButton.superclass.initComponent.call(this);
  982.         this.on('click', this.toggleSelected, this);
  983.     },
  984.     // private
  985.     checkHandler : function(item, pressed){
  986.         if(pressed){
  987.             this.setActiveItem(item);
  988.         }
  989.     },
  990.     /**
  991.      * This is normally called internally on button click, but can be called externally to advance the button's
  992.      * active item programmatically to the next one in the menu.  If the current item is the last one in the menu
  993.      * the active item will be set to the first item in the menu.
  994.      */
  995.     toggleSelected : function(){
  996.         var m = this.menu;
  997.         m.render();
  998.         // layout if we haven't before so the items are active
  999.         if(!m.hasLayout){
  1000.             m.doLayout();
  1001.         }
  1002.         
  1003.         var nextIdx, checkItem;
  1004.         for (var i = 1; i < this.itemCount; i++) {
  1005.             nextIdx = (this.activeItem.itemIndex + i) % this.itemCount;
  1006.             // check the potential item
  1007.             checkItem = m.items.itemAt(nextIdx);
  1008.             // if its not disabled then check it.
  1009.             if (!checkItem.disabled) {
  1010.                 checkItem.setChecked(true);
  1011.                 break;
  1012.             }
  1013.         }
  1014.     }
  1015. });
  1016. Ext.reg('cycle', Ext.CycleButton);