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

中间件编程

开发平台:

JavaScript

  1. /*!  * Ext JS Library 3.0.0  * Copyright(c) 2006-2009 Ext JS, LLC  * licensing@extjs.com  * http://www.extjs.com/license  */ /**  * @class Ext.Button  * @extends Ext.BoxComponent  * Simple Button class  * @cfg {String} text The button text to be used as innerHTML (html tags are accepted)  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:'x-btn-text-icon')  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event).  * The handler is passed the following parameters:<div class="mdetail-params"><ul>  * <li><code>b</code> : Button<div class="sub-desc">This Button.</div></li>  * <li><code>e</code> : EventObject<div class="sub-desc">The click event.</div></li>  * </ul></div>  * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the handler is executed. Defaults to this Button.  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width).  * See also {@link Ext.Panel}.<tt>{@link Ext.Panel#minButtonWidth minButtonWidth}</tt>.  * @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  * @cfg {Boolean} hidden True to start hidden (defaults to false)  * @cfg {Boolean} disabled True to start disabled (defaults to false)  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed)  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be  * a {@link Ext.util.ClickRepeater ClickRepeater} config object (defaults to false).  * @constructor  * Create a new button  * @param {Object} config The config object  * @xtype button  */ Ext.Button = Ext.extend(Ext.BoxComponent, {     /**      * Read-only. True if this button is hidden      * @type Boolean      */     hidden : false,     /**      * Read-only. True if this button is disabled      * @type Boolean      */     disabled : false,     /**      * Read-only. True if this button is pressed (only if enableToggle = true)      * @type Boolean      */     pressed : false,     /**      * The Button's owner {@link Ext.Panel} (defaults to undefined, and is set automatically when      * the Button is added to a container).  Read-only.      * @type Ext.Panel      * @property ownerCt      */     /**      * @cfg {Number} tabIndex Set a DOM tabIndex for this button (defaults to undefined)      */     /**      * @cfg {Boolean} allowDepress      * False to not allow a pressed Button to be depressed (defaults to undefined). Only valid when {@link #enableToggle} is true.      */     /**      * @cfg {Boolean} enableToggle      * True to enable pressed/not pressed toggling (defaults to false)      */     enableToggle: false,     /**      * @cfg {Function} toggleHandler      * Function called when a Button with {@link #enableToggle} set to true is clicked. Two arguments are passed:<ul class="mdetail-params">      * <li><b>button</b> : Ext.Button<div class="sub-desc">this Button object</div></li>      * <li><b>state</b> : Boolean<div class="sub-desc">The next state if the Button, true means pressed.</div></li>      * </ul>      */     /**      * @cfg {Mixed} menu      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).      */     /**      * @cfg {String} menuAlign      * The position to align the menu to (see {@link Ext.Element#alignTo} for more details, defaults to 'tl-bl?').      */     menuAlign : 'tl-bl?',     /**      * @cfg {String} overflowText If used in a {@link Ext.Toolbar Toolbar}, the      * text to be used if this item is shown in the overflow menu. See also      * {@link Ext.Toolbar.Item}.<code>{@link Ext.Toolbar.Item#overflowText overflowText}</code>.      */     /**      * @cfg {String} iconCls      * A css class which sets a background image to be used as the icon for this button      */     /**      * @cfg {String} type      * submit, reset or button - defaults to 'button'      */     type : 'button',     // private     menuClassTarget: 'tr:nth(2)',     /**      * @cfg {String} clickEvent      * The type of event to map to the button's event handler (defaults to 'click')      */     clickEvent : 'click',     /**      * @cfg {Boolean} handleMouseEvents      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)      */     handleMouseEvents : true,     /**      * @cfg {String} tooltipType      * The type of tooltip to use. Either 'qtip' (default) for QuickTips or 'title' for title attribute.      */     tooltipType : 'qtip',     /**      * @cfg {String} buttonSelector      * <p>(Optional) A {@link Ext.DomQuery DomQuery} selector which is used to extract the active, clickable element from the      * DOM structure created.</p>      * <p>When a custom {@link #template} is used, you  must ensure that this selector results in the selection of      * a focussable element.</p>      * <p>Defaults to <b><tt>"button:first-child"</tt></b>.</p>      */     buttonSelector : 'button:first-child',     /**      * @cfg {String} scale      * <p>(Optional) The size of the Button. Three values are allowed:</p>      * <ul class="mdetail-params">      * <li>'small'<div class="sub-desc">Results in the button element being 16px high.</div></li>      * <li>'medium'<div class="sub-desc">Results in the button element being 24px high.</div></li>      * <li>'large'<div class="sub-desc">Results in the button element being 32px high.</div></li>      * </ul>      * <p>Defaults to <b><tt>'small'</tt></b>.</p>      */     scale: 'small',     /**      * @cfg {String} iconAlign      * <p>(Optional) The side of the Button box to render the icon. Four values are allowed:</p>      * <ul class="mdetail-params">      * <li>'top'<div class="sub-desc"></div></li>      * <li>'right'<div class="sub-desc"></div></li>      * <li>'bottom'<div class="sub-desc"></div></li>      * <li>'left'<div class="sub-desc"></div></li>      * </ul>      * <p>Defaults to <b><tt>'left'</tt></b>.</p>      */     iconAlign : 'left',     /**      * @cfg {String} arrowAlign      * <p>(Optional) The side of the Button box to render the arrow if the button has an associated {@link #menu}.      * Two values are allowed:</p>      * <ul class="mdetail-params">      * <li>'right'<div class="sub-desc"></div></li>      * <li>'bottom'<div class="sub-desc"></div></li>      * </ul>      * <p>Defaults to <b><tt>'right'</tt></b>.</p>      */     arrowAlign : 'right',     /**      * @cfg {Ext.Template} template (Optional)      * <p>A {@link Ext.Template Template} used to create the Button's DOM structure.</p>      * Instances, or subclasses which need a different DOM structure may provide a different      * template layout in conjunction with an implementation of {@link #getTemplateArgs}.      * @type Ext.Template      * @property template      */     /**      * @cfg {String} cls      * A CSS class string to apply to the button's main element.      */     /**      * @property menu      * @type Menu      * The {@link Ext.menu.Menu Menu} object associated with this Button when configured with the {@link #menu} config option.      */     initComponent : function(){         Ext.Button.superclass.initComponent.call(this);         this.addEvents(             /**              * @event click              * Fires when this button is clicked              * @param {Button} this              * @param {EventObject} e The click event              */             'click',             /**              * @event toggle              * Fires when the 'pressed' state of this button changes (only if enableToggle = true)              * @param {Button} this              * @param {Boolean} pressed              */             'toggle',             /**              * @event mouseover              * Fires when the mouse hovers over the button              * @param {Button} this              * @param {Event} e The event object              */             'mouseover',             /**              * @event mouseout              * Fires when the mouse exits the button              * @param {Button} this              * @param {Event} e The event object              */             'mouseout',             /**              * @event menushow              * If this button has a menu, this event fires when it is shown              * @param {Button} this              * @param {Menu} menu              */             'menushow',             /**              * @event menuhide              * If this button has a menu, this event fires when it is hidden              * @param {Button} this              * @param {Menu} menu              */             'menuhide',             /**              * @event menutriggerover              * If this button has a menu, this event fires when the mouse enters the menu triggering element              * @param {Button} this              * @param {Menu} menu              * @param {EventObject} e              */             'menutriggerover',             /**              * @event menutriggerout              * If this button has a menu, this event fires when the mouse leaves the menu triggering element              * @param {Button} this              * @param {Menu} menu              * @param {EventObject} e              */             'menutriggerout'         );         if(this.menu){             this.menu = Ext.menu.MenuMgr.get(this.menu);         }         if(Ext.isString(this.toggleGroup)){             this.enableToggle = true;         }     }, /**   * <p>This method returns an object which provides substitution parameters for the {@link #template Template} used   * to create this Button's DOM structure.</p>   * <p>Instances or subclasses which use a different Template to create a different DOM structure may need to provide their   * own implementation of this method.</p>   * <p>The default implementation which provides data for the default {@link #template} returns an Array containing the   * following items:</p><div class="mdetail-params"><ul>   * <li>The Button's {@link #text}</li>   * <li>The &lt;button&gt;'s {@link #type}</li>   * <li>The {@link iconCls} applied to the &lt;button&gt; {@link #btnEl element}</li>   * <li>The {@link #cls} applied to the Button's main {@link #getEl Element}</li>   * <li>A CSS class name controlling the Button's {@link #scale} and {@link #iconAlign icon alignment}</li>   * <li>A CSS class name which applies an arrow to the Button if configured with a {@link #menu}</li>   * </ul></div>   * @return {Object} Substitution data for a Template.  */     getTemplateArgs : function(){         var cls = (this.cls || '');         cls += (this.iconCls || this.icon) ? (this.text ? ' x-btn-text-icon' : ' x-btn-icon') : ' x-btn-noicon';         if(this.pressed){             cls += ' x-btn-pressed';         }         return [this.text || '&#160;', this.type, this.iconCls || '', cls, 'x-btn-' + this.scale + ' x-btn-icon-' + this.scale + '-' + this.iconAlign, this.getMenuClass()];     },     // protected     getMenuClass : function(){         return this.menu ? (this.arrowAlign != 'bottom' ? 'x-btn-arrow' : 'x-btn-arrow-bottom') : '';     },     // private     onRender : function(ct, position){         if(!this.template){             if(!Ext.Button.buttonTemplate){                 // hideous table template                 Ext.Button.buttonTemplate = new Ext.Template(                     '<table cellspacing="0" class="x-btn {3}"><tbody class="{4}">',                     '<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>',                     '<tr><td class="x-btn-ml"><i>&#160;</i></td><td class="x-btn-mc"><em class="{5}" unselectable="on"><button class="x-btn-text {2}" type="{1}">{0}</button></em></td><td class="x-btn-mr"><i>&#160;</i></td></tr>',                     '<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>',                     "</tbody></table>");                 Ext.Button.buttonTemplate.compile();             }             this.template = Ext.Button.buttonTemplate;         }         var btn, targs = this.getTemplateArgs();         if(position){             btn = this.template.insertBefore(position, targs, true);         }else{             btn = this.template.append(ct, targs, true);         }         /**          * An {@link Ext.Element Element} encapsulating the Button's clickable element. By default,          * this references a <tt>&lt;button&gt;</tt> element. Read only.          * @type Ext.Element          * @property btnEl          */         this.btnEl = btn.child(this.buttonSelector);         this.mon(this.btnEl, {             scope: this,             focus: this.onFocus,             blur: this.onBlur         });         this.initButtonEl(btn, this.btnEl);         Ext.ButtonToggleMgr.register(this);     },     // private     initButtonEl : function(btn, btnEl){         this.el = btn;         if(this.id){             this.el.dom.id = this.el.id = this.id;         }         if(this.icon){             btnEl.setStyle('background-image', 'url(' +this.icon +')');         }         if(this.tabIndex !== undefined){             btnEl.dom.tabIndex = this.tabIndex;         }         if(this.tooltip){             this.setTooltip(this.tooltip, true);         }         if(this.handleMouseEvents){             this.mon(btn, {                 scope: this,                 mouseover: this.onMouseOver,                 mousedown: this.onMouseDown             });                          // new functionality for monitoring on the document level             //this.mon(btn, 'mouseout', this.onMouseOut, this);         }         if(this.menu){             this.mon(this.menu, {                 scope: this,                 show: this.onMenuShow,                 hide: this.onMenuHide             });         }         if(this.repeat){             var repeater = new Ext.util.ClickRepeater(btn, Ext.isObject(this.repeat) ? this.repeat : {});             this.mon(repeater, 'click', this.onClick, this);         }                  this.mon(btn, this.clickEvent, this.onClick, this);     },     // private     afterRender : function(){         Ext.Button.superclass.afterRender.call(this);         this.doAutoWidth();     },     /**      * Sets the CSS class that provides a background image to use as the button's icon.  This method also changes      * the value of the {@link iconCls} config internally.      * @param {String} cls The CSS class providing the icon image      * @return {Ext.Button} this      */     setIconClass : function(cls){         if(this.el){             this.btnEl.replaceClass(this.iconCls, cls);         }         this.iconCls = cls;         return this;     },     /**      * Sets the tooltip for this Button.      * @param {String/Object} tooltip. This may be:<div class="mdesc-details"><ul>      * <li><b>String</b> : A string to be used as innerHTML (html tags are accepted) to show in a tooltip</li>      * <li><b>Object</b> : A configuration object for {@link Ext.QuickTips#register}.</li>      * </ul></div>      * @return {Ext.Button} this      */     setTooltip : function(tooltip, /* private */ initial){         if(this.rendered){             if(!initial){                 this.clearTip();             }             if(Ext.isObject(tooltip)){                 Ext.QuickTips.register(Ext.apply({                       target: this.btnEl.id                 }, tooltip));                 this.tooltip = tooltip;             }else{                 this.btnEl.dom[this.tooltipType] = tooltip;             }         }else{             this.tooltip = tooltip;         }         return this;     },          // private     clearTip: function(){         if(Ext.isObject(this.tooltip)){             Ext.QuickTips.unregister(this.btnEl);         }     },          // private     beforeDestroy: function(){         if(this.rendered){             this.clearTip();         }         Ext.destroy(this.menu, this.repeater);     },     // private     onDestroy : function(){         var doc = Ext.getDoc();         doc.un('mouseover', this.monitorMouseOver, this);         doc.un('mouseup', this.onMouseUp, this);         if(this.rendered){             Ext.ButtonToggleMgr.unregister(this);         }     },     // private     doAutoWidth : function(){         if(this.el && this.text && this.width === undefined){             this.el.setWidth('auto');             if(Ext.isIE7 && Ext.isStrict){                 var ib = this.btnEl;                 if(ib && ib.getWidth() > 20){                     ib.clip();                     ib.setWidth(Ext.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));                 }             }             if(this.minWidth){                 if(this.el.getWidth() < this.minWidth){                     this.el.setWidth(this.minWidth);                 }             }         }     },     /**      * Assigns this Button's click handler      * @param {Function} handler The function to call when the button is clicked      * @param {Object} scope (optional) Scope for the function passed in      * @return {Ext.Button} this      */     setHandler : function(handler, scope){         this.handler = handler;         this.scope = scope;         return this;     },     /**      * Sets this Button's text      * @param {String} text The button text      * @return {Ext.Button} this      */     setText : function(text){         this.text = text;         if(this.el){             this.el.child('td.x-btn-mc ' + this.buttonSelector).update(text);         }         this.doAutoWidth();         return this;     },     /**      * Gets the text for this Button      * @return {String} The button text      */     getText : function(){         return this.text;     },     /**      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.      * @param {Boolean} state (optional) Force a particular state      * @param {Boolean} supressEvent (optional) True to stop events being fired when calling this method.      * @return {Ext.Button} this      */     toggle : function(state, suppressEvent){         state = state === undefined ? !this.pressed : !!state;         if(state != this.pressed){             this.el[state ? 'addClass' : 'removeClass']('x-btn-pressed');             this.pressed = state;             if(!suppressEvent){                 this.fireEvent('toggle', this, state);                 if(this.toggleHandler){                     this.toggleHandler.call(this.scope || this, this, state);                 }             }         }         return this;     },     /**      * Focus the button      */     focus : function(){         this.btnEl.focus();     },     // private     onDisable : function(){         this.onDisableChange(true);     },     // private     onEnable : function(){         this.onDisableChange(false);     },          onDisableChange : function(disabled){         if(this.el){             if(!Ext.isIE6 || !this.text){                 this.el[disabled ? 'addClass' : 'removeClass'](this.disabledClass);             }             this.el.dom.disabled = disabled;         }         this.disabled = disabled;     },     /**      * Show this button's menu (if it has one)      */     showMenu : function(){         if(this.rendered && this.menu){             if(this.tooltip){                 Ext.QuickTips.getQuickTip().cancelShow(this.btnEl);             }             this.menu.show(this.el, this.menuAlign);         }         return this;     },     /**      * Hide this button's menu (if it has one)      */     hideMenu : function(){         if(this.menu){             this.menu.hide();         }         return this;     },     /**      * Returns true if the button has a menu and it is visible      * @return {Boolean}      */     hasVisibleMenu : function(){         return this.menu && this.menu.isVisible();     },     // private     onClick : function(e){         if(e){             e.preventDefault();         }         if(e.button !== 0){             return;         }         if(!this.disabled){             if(this.enableToggle && (this.allowDepress !== false || !this.pressed)){                 this.toggle();             }             if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){                 this.showMenu();             }             this.fireEvent('click', this, e);             if(this.handler){                 //this.el.removeClass('x-btn-over');                 this.handler.call(this.scope || this, this, e);             }         }     },     // private     isMenuTriggerOver : function(e, internal){         return this.menu && !internal;     },     // private     isMenuTriggerOut : function(e, internal){         return this.menu && !internal;     },     // private     onMouseOver : function(e){         if(!this.disabled){             var internal = e.within(this.el,  true);             if(!internal){                 this.el.addClass('x-btn-over');                 if(!this.monitoringMouseOver){                     Ext.getDoc().on('mouseover', this.monitorMouseOver, this);                     this.monitoringMouseOver = true;                 }                 this.fireEvent('mouseover', this, e);             }             if(this.isMenuTriggerOver(e, internal)){                 this.fireEvent('menutriggerover', this, this.menu, e);             }         }     },     // private     monitorMouseOver : function(e){         if(e.target != this.el.dom && !e.within(this.el)){             if(this.monitoringMouseOver){                 Ext.getDoc().un('mouseover', this.monitorMouseOver, this);                 this.monitoringMouseOver = false;             }             this.onMouseOut(e);         }     },     // private     onMouseOut : function(e){         var internal = e.within(this.el) && e.target != this.el.dom;         this.el.removeClass('x-btn-over');         this.fireEvent('mouseout', this, e);         if(this.isMenuTriggerOut(e, internal)){             this.fireEvent('menutriggerout', this, this.menu, e);         }     },     // private     onFocus : function(e){         if(!this.disabled){             this.el.addClass('x-btn-focus');         }     },     // private     onBlur : function(e){         this.el.removeClass('x-btn-focus');     },     // private     getClickEl : function(e, isUp){        return this.el;     },     // private     onMouseDown : function(e){         if(!this.disabled && e.button === 0){             this.getClickEl(e).addClass('x-btn-click');             Ext.getDoc().on('mouseup', this.onMouseUp, this);         }     },     // private     onMouseUp : function(e){         if(e.button === 0){             this.getClickEl(e, true).removeClass('x-btn-click');             Ext.getDoc().un('mouseup', this.onMouseUp, this);         }     },     // private     onMenuShow : function(e){         this.ignoreNextClick = 0;         this.el.addClass('x-btn-menu-active');         this.fireEvent('menushow', this, this.menu);     },     // private     onMenuHide : function(e){         this.el.removeClass('x-btn-menu-active');         this.ignoreNextClick = this.restoreClick.defer(250, this);         this.fireEvent('menuhide', this, this.menu);     },     // private     restoreClick : function(){         this.ignoreNextClick = 0;     }     /**      * @cfg {String} autoEl @hide      */ }); Ext.reg('button', Ext.Button); // Private utility class used by Button Ext.ButtonToggleMgr = function(){    var groups = {};    function toggleGroup(btn, state){        if(state){            var g = groups[btn.toggleGroup];            for(var i = 0, l = g.length; i < l; i++){                if(g[i] != btn){                    g[i].toggle(false);                }            }        }    }    return {        register : function(btn){            if(!btn.toggleGroup){                return;            }            var g = groups[btn.toggleGroup];            if(!g){                g = groups[btn.toggleGroup] = [];            }            g.push(btn);            btn.on('toggle', toggleGroup);        },        unregister : function(btn){            if(!btn.toggleGroup){                return;            }            var g = groups[btn.toggleGroup];            if(g){                g.remove(btn);                btn.un('toggle', toggleGroup);            }        },        /**         * Gets the pressed button in the passed group or null         * @param {String} group         * @return Button         */        getPressed : function(group){            var g = groups[group];            if(g){                for(var i = 0, len = g.length; i < len; i++){                    if(g[i].pressed === true){                        return g[i];                    }                }            }            return null;        }    }; }();/**
  2.  * @class Ext.SplitButton
  3.  * @extends Ext.Button
  4.  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
  5.  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
  6.  * options to the primary button action, but any custom handler can provide the arrowclick implementation.  Example usage:
  7.  * <pre><code>
  8. // display a dropdown menu:
  9. new Ext.SplitButton({
  10. renderTo: 'button-ct', // the container id
  11.     text: 'Options',
  12.     handler: optionsHandler, // handle a click on the button itself
  13.     menu: new Ext.menu.Menu({
  14.         items: [
  15.          // these items will render as dropdown menu items when the arrow is clicked:
  16.         {text: 'Item 1', handler: item1Handler},
  17.         {text: 'Item 2', handler: item2Handler}
  18.         ]
  19.     })
  20. });
  21. // Instead of showing a menu, you provide any type of custom
  22. // functionality you want when the dropdown arrow is clicked:
  23. new Ext.SplitButton({
  24. renderTo: 'button-ct',
  25.     text: 'Options',
  26.     handler: optionsHandler,
  27.     arrowHandler: myCustomHandler
  28. });
  29. </code></pre>
  30.  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
  31.  * @cfg {String} arrowTooltip The title attribute of the arrow
  32.  * @constructor
  33.  * Create a new menu button
  34.  * @param {Object} config The config object
  35.  * @xtype splitbutton
  36.  */
  37. Ext.SplitButton = Ext.extend(Ext.Button, {
  38. // private
  39.     arrowSelector : 'em',
  40.     split: true,
  41.     // private
  42.     initComponent : function(){
  43.         Ext.SplitButton.superclass.initComponent.call(this);
  44.         /**
  45.          * @event arrowclick
  46.          * Fires when this button's arrow is clicked
  47.          * @param {MenuButton} this
  48.          * @param {EventObject} e The click event
  49.          */
  50.         this.addEvents("arrowclick");
  51.     },
  52.     // private
  53.     onRender : function(){
  54.         Ext.SplitButton.superclass.onRender.apply(this, arguments);
  55.         if(this.arrowTooltip){
  56.             this.el.child(this.arrowSelector).dom[this.tooltipType] = this.arrowTooltip;
  57.         }
  58.     },
  59.     /**
  60.      * Sets this button's arrow click handler.
  61.      * @param {Function} handler The function to call when the arrow is clicked
  62.      * @param {Object} scope (optional) Scope for the function passed above
  63.      */
  64.     setArrowHandler : function(handler, scope){
  65.         this.arrowHandler = handler;
  66.         this.scope = scope;
  67.     },
  68.     getMenuClass : function(){
  69.         return 'x-btn-split' + (this.arrowAlign == 'bottom' ? '-bottom' : '');
  70.     },
  71.     isClickOnArrow : function(e){
  72.         return this.arrowAlign != 'bottom' ?
  73.                e.getPageX() > this.el.child(this.buttonSelector).getRegion().right :
  74.                e.getPageY() > this.el.child(this.buttonSelector).getRegion().bottom;
  75.     },
  76.     // private
  77.     onClick : function(e, t){
  78.         e.preventDefault();
  79.         if(!this.disabled){
  80.             if(this.isClickOnArrow(e)){
  81.                 if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){
  82.                     this.showMenu();
  83.                 }
  84.                 this.fireEvent("arrowclick", this, e);
  85.                 if(this.arrowHandler){
  86.                     this.arrowHandler.call(this.scope || this, this, e);
  87.                 }
  88.             }else{
  89.                 if(this.enableToggle){
  90.                     this.toggle();
  91.                 }
  92.                 this.fireEvent("click", this, e);
  93.                 if(this.handler){
  94.                     this.handler.call(this.scope || this, this, e);
  95.                 }
  96.             }
  97.         }
  98.     },
  99.     // private
  100.     isMenuTriggerOver : function(e){
  101.         return this.menu && e.target.tagName == 'em';
  102.     },
  103.     // private
  104.     isMenuTriggerOut : function(e, internal){
  105.         return this.menu && e.target.tagName != 'em';
  106.     }
  107. });
  108. Ext.reg('splitbutton', Ext.SplitButton);/**
  109.  * @class Ext.CycleButton
  110.  * @extends Ext.SplitButton
  111.  * A specialized SplitButton that contains a menu of {@link Ext.menu.CheckItem} elements.  The button automatically
  112.  * cycles through each menu item on click, raising the button's {@link #change} event (or calling the button's
  113.  * {@link #changeHandler} function, if supplied) for the active menu item. Clicking on the arrow section of the
  114.  * button displays the dropdown menu just like a normal SplitButton.  Example usage:
  115.  * <pre><code>
  116. var btn = new Ext.CycleButton({
  117.     showText: true,
  118.     prependText: 'View as ',
  119.     items: [{
  120.         text:'text only',
  121.         iconCls:'view-text',
  122.         checked:true
  123.     },{
  124.         text:'HTML',
  125.         iconCls:'view-html'
  126.     }],
  127.     changeHandler:function(btn, item){
  128.         Ext.Msg.alert('Change View', item.text);
  129.     }
  130. });
  131. </code></pre>
  132.  * @constructor
  133.  * Create a new split button
  134.  * @param {Object} config The config object
  135.  * @xtype cycle
  136.  */
  137. Ext.CycleButton = Ext.extend(Ext.SplitButton, {
  138.     /**
  139.      * @cfg {Array} items An array of {@link Ext.menu.CheckItem} <b>config</b> objects to be used when creating the
  140.      * button's menu items (e.g., {text:'Foo', iconCls:'foo-icon'})
  141.      */
  142.     /**
  143.      * @cfg {Boolean} showText True to display the active item's text as the button text (defaults to false)
  144.      */
  145.     /**
  146.      * @cfg {String} prependText A static string to prepend before the active item's text when displayed as the
  147.      * button's text (only applies when showText = true, defaults to '')
  148.      */
  149.     /**
  150.      * @cfg {Function} changeHandler A callback function that will be invoked each time the active menu
  151.      * item in the button's menu has changed.  If this callback is not supplied, the SplitButton will instead
  152.      * fire the {@link #change} event on active item change.  The changeHandler function will be called with the
  153.      * following argument list: (SplitButton this, Ext.menu.CheckItem item)
  154.      */
  155.     /**
  156.      * @cfg {String} forceIcon A css class which sets an image to be used as the static icon for this button.  This
  157.      * icon will always be displayed regardless of which item is selected in the dropdown list.  This overrides the 
  158.      * default behavior of changing the button's icon to match the selected item's icon on change.
  159.      */
  160.     /**
  161.      * @property menu
  162.      * @type Menu
  163.      * The {@link Ext.menu.Menu Menu} object used to display the {@link Ext.menu.CheckItem CheckItems} representing the available choices.
  164.      */
  165.     // private
  166.     getItemText : function(item){
  167.         if(item && this.showText === true){
  168.             var text = '';
  169.             if(this.prependText){
  170.                 text += this.prependText;
  171.             }
  172.             text += item.text;
  173.             return text;
  174.         }
  175.         return undefined;
  176.     },
  177.     /**
  178.      * Sets the button's active menu item.
  179.      * @param {Ext.menu.CheckItem} item The item to activate
  180.      * @param {Boolean} suppressEvent True to prevent the button's change event from firing (defaults to false)
  181.      */
  182.     setActiveItem : function(item, suppressEvent){
  183.         if(typeof item != 'object'){
  184.             item = this.menu.items.get(item);
  185.         }
  186.         if(item){
  187.             if(!this.rendered){
  188.                 this.text = this.getItemText(item);
  189.                 this.iconCls = item.iconCls;
  190.             }else{
  191.                 var t = this.getItemText(item);
  192.                 if(t){
  193.                     this.setText(t);
  194.                 }
  195.                 this.setIconClass(item.iconCls);
  196.             }
  197.             this.activeItem = item;
  198.             if(!item.checked){
  199.                 item.setChecked(true, true);
  200.             }
  201.             if(this.forceIcon){
  202.                 this.setIconClass(this.forceIcon);
  203.             }
  204.             if(!suppressEvent){
  205.                 this.fireEvent('change', this, item);
  206.             }
  207.         }
  208.     },
  209.     /**
  210.      * Gets the currently active menu item.
  211.      * @return {Ext.menu.CheckItem} The active item
  212.      */
  213.     getActiveItem : function(){
  214.         return this.activeItem;
  215.     },
  216.     // private
  217.     initComponent : function(){
  218.         this.addEvents(
  219.             /**
  220.              * @event change
  221.              * Fires after the button's active menu item has changed.  Note that if a {@link #changeHandler} function
  222.              * is set on this CycleButton, it will be called instead on active item change and this change event will
  223.              * not be fired.
  224.              * @param {Ext.CycleButton} this
  225.              * @param {Ext.menu.CheckItem} item The menu item that was selected
  226.              */
  227.             "change"
  228.         );
  229.         if(this.changeHandler){
  230.             this.on('change', this.changeHandler, this.scope||this);
  231.             delete this.changeHandler;
  232.         }
  233.         this.itemCount = this.items.length;
  234.         this.menu = {cls:'x-cycle-menu', items:[]};
  235.         var checked;
  236.         for(var i = 0, len = this.itemCount; i < len; i++){
  237.             var item = this.items[i];
  238.             item.group = item.group || this.id;
  239.             item.itemIndex = i;
  240.             item.checkHandler = this.checkHandler;
  241.             item.scope = this;
  242.             item.checked = item.checked || false;
  243.             this.menu.items.push(item);
  244.             if(item.checked){
  245.                 checked = item;
  246.             }
  247.         }
  248.         this.setActiveItem(checked, true);
  249.         Ext.CycleButton.superclass.initComponent.call(this);
  250.         this.on('click', this.toggleSelected, this);
  251.     },
  252.     // private
  253.     checkHandler : function(item, pressed){
  254.         if(pressed){
  255.             this.setActiveItem(item);
  256.         }
  257.     },
  258.     /**
  259.      * This is normally called internally on button click, but can be called externally to advance the button's
  260.      * active item programmatically to the next one in the menu.  If the current item is the last one in the menu
  261.      * the active item will be set to the first item in the menu.
  262.      */
  263.     toggleSelected : function(){
  264.         this.menu.render();
  265.         
  266.         var nextIdx, checkItem;
  267.         for (var i = 1; i < this.itemCount; i++) {
  268.             nextIdx = (this.activeItem.itemIndex + i) % this.itemCount;
  269.             // check the potential item
  270.             checkItem = this.menu.items.itemAt(nextIdx);
  271.             // if its not disabled then check it.
  272.             if (!checkItem.disabled) {
  273.                 checkItem.setChecked(true);
  274.                 break;
  275.             }
  276.         }
  277.     }
  278. });
  279. Ext.reg('cycle', Ext.CycleButton);