/** * A specialized SplitButton that contains a menu of {@link Ext.menu.CheckItem} elements. The button automatically * cycles through each menu item on click, raising the button's {@link #change} event (or calling the button's * {@link #changeHandler} function, if supplied) for the active menu item. Clicking on the arrow section of the * button displays the dropdown menu just like a normal SplitButton. Example usage: * * @example * Ext.create('Ext.button.Cycle', { * showText: true, * prependText: 'View as ', * renderTo: Ext.getBody(), * menu: { * id: 'view-type-menu', * items: [{ * text: 'text only', * iconCls: 'view-text', * checked: true * },{ * text: 'HTML', * iconCls: 'view-html' * }] * }, * changeHandler: function(cycleBtn, activeItem) { * Ext.Msg.alert('Change View', activeItem.text); * } * }); */Ext.define('Ext.button.Cycle', { /* Begin Definitions */ alias: 'widget.cycle', extend: 'Ext.button.Split', alternateClassName: 'Ext.CycleButton', /* End Definitions */ /** * @cfg {Object[]} items * An array of {@link Ext.menu.CheckItem} **config** objects to be used when creating the button's menu items (e.g., * `{text:'Foo', iconCls:'foo-icon'}`) * * @deprecated 4.0 Use the {@link #cfg-menu} config instead. All menu items will be created as * {@link Ext.menu.CheckItem CheckItems}. */ /** * @cfg {Boolean} [showText=false] * True to display the active item's text as the button text. The Button will show its * configured {@link #text} if this config is omitted. */ /** * @cfg {String} [prependText=''] * A static string to prepend before the active item's text when displayed as the button's text (only applies when * showText = true). */ /** * @cfg {Function/String} [changeHandler=undefined] * A callback function that will be invoked each time the active menu item in the button's menu has changed. If this * callback is not supplied, the SplitButton will instead fire the {@link #change} event on active item change. The * changeHandler function will be called with the following argument list: (SplitButton this, Ext.menu.CheckItem * item) * @controllable */ /** * @cfg {String} forceIcon * A css class which sets an image to be used as the static icon for this button. This icon will always be displayed * regardless of which item is selected in the dropdown list. This overrides the default behavior of changing the * button's icon to match the selected item's icon on change. */ /** * @cfg {Number/String} forceGlyph * The charCode to be used as the static icon for this button. This icon will always be * displayed regardless of which item is selected in the dropdown list. This override * the default behavior of changing the button's icon to match the selected item's icon * on change. This property expects a format consistent with that of {@link #glyph} */ /** * @property {Ext.menu.Menu} menu * The {@link Ext.menu.Menu Menu} object used to display the {@link Ext.menu.CheckItem CheckItems} representing the * available choices. */ /** * @event change * Fires after the button's active menu item has changed. Note that if a {@link #changeHandler} function is * set on this CycleButton, it will be called instead on active item change and this change event will not * be fired. * @param {Ext.button.Cycle} this * @param {Ext.menu.CheckItem} item The menu item that was selected */ /** * @private */ getButtonText: function(item) { var me = this, text = ''; if (item && me.showText === true) { if (me.prependText) { text += me.prependText; } text += item.text; return text; } return me.text; }, /** * Sets the button's active menu item. * @param {Ext.menu.CheckItem} item The item to activate * @param {Boolean} [suppressEvent=false] True to prevent the {@link #change} event and {@link #changeHandler} from firing. */ setActiveItem: function(item, suppressEvent) { var me = this, changeHandler = me.changeHandler, forceIcon = me.forceIcon, forceGlyph = me.forceGlyph; me.settingActive = true; if (!Ext.isObject(item)) { item = me.menu.getComponent(item); } if (item) { me.setText(me.getButtonText(item)); me.setIconCls(forceIcon ? forceIcon : item.iconCls); me.setGlyph(forceGlyph ? forceGlyph : item.glyph); me.activeItem = item; if (!item.checked) { item.setChecked(true, false); } if (!suppressEvent) { if (changeHandler) { Ext.callback(changeHandler, me.scope, [me, item], 0, me); } me.fireEvent('change', me, item); } } me.settingActive = false; }, /** * Gets the currently active menu item. * @return {Ext.menu.CheckItem} The active item */ getActiveItem: function() { return this.activeItem; }, /** * @private */ initComponent: function() { var me = this, checked = 0, items, i, iLen, item; //<debug> // Ext JS Cycle buttons are implemented in a way that clashes with WAI-ARIA requirements, // so we warn the developer about that. Ext.ariaWarn(me, "Using Cycle buttons is not recommended in accessible " + "applications, because their behavior conflicts " + "with accessibility best practices. See WAI-ARIA 1.0 " + "Authoring guide: http://www.w3.org/TR/wai-aria-practices/#menubutton" ); //</debug> // Allow them to specify a menu config which is a standard Button config. // Remove direct use of "items" in 5.0. items = (me.menu.items || []).concat(me.items || []); me.menu = Ext.applyIf({ cls: Ext.baseCSSPrefix + 'cycle-menu', items: [] }, me.menu); iLen = items.length; // Convert all items to CheckItems for (i = 0; i < iLen; i++) { item = items[i]; item = Ext.applyIf({ group : me.id, itemIndex : i, checkHandler : me.checkHandler, scope : me, checked : item.checked || false }, item); me.menu.items.push(item); if (item.checked) { checked = i; } } me.itemCount = me.menu.items.length; me.callParent(arguments); me.on('click', me.toggleSelected, me); me.setActiveItem(checked, true); }, /** * @private */ checkHandler: function(item, pressed) { if (pressed && !this.settingActive) { this.setActiveItem(item); } }, /** * This is normally called internally on button click, but can be called externally to advance the button's active * item programmatically to the next one in the menu. If the current item is the last one in the menu the active * item will be set to the first item in the menu. */ toggleSelected: function() { var me = this, m = me.menu, checkItem; checkItem = me.activeItem.next(':not([disabled])') || m.items.getAt(0); checkItem.setChecked(true); }});