* This is a supporting class for {@link Ext.ux.grid.filter.ListFilter}. * Although not listed as configuration options for this class, this class * also accepts all configuration options from {@link Ext.ux.grid.filter.ListFilter}. */ Ext.define('Ext.ux.grid.menu.ListMenu', { extend: 'Ext.menu.Menu', * @cfg {String} idField * Defaults to 'id'. */ idField : 'id', * @cfg {String} labelField * Defaults to 'text'. */ labelField : 'text', * @cfg {String} paramPrefix * Defaults to 'Loading...'. */ loadingText : 'Loading...', * @cfg {Boolean} loadOnShow * Defaults to true. */ loadOnShow : true, * @cfg {Boolean} single * Specify true to group all items in this list into a single-select * radio button group. Defaults to false. */ single : false, var me = this, options, i, len, value; me.selected = []; me.addEvents( * @event checkchange * Fires when there is a change in checked items from this list * @param {Object} item Ext.menu.CheckItem * @param {Object} checked The checked value that was set */ 'checkchange' ); me.callParent(arguments); // A ListMenu which is completely unconfigured acquires its store from the unique values of its field in the store if (!me.store && !me.options) { me.options = me.grid.store.collect(me.dataIndex, false, true); } if (!me.store && me.options) { options = []; for(i = 0, len = me.options.length; i < len; i++) { value = me.options[i]; switch (Ext.type(value)) { case 'array': options.push(value); break; case 'object': options.push([value[me.idField], value[me.labelField]]); break; default: if (value != null) { options.push([value, value]); } } } me.store = Ext.create('Ext.data.ArrayStore', { fields: [me.idField, me.labelField], data: options, listeners: { load: me.onLoad, scope: me } }); me.loaded = true; me.autoStore = true; } else { me.add({ text: me.loadingText, iconCls: 'loading-indicator' }); me.store.on('load', me.onLoad, me); } }, var me = this, store = me.store; if (store) { if (me.autoStore) { store.destroyStore(); } else { store.un('unload', me.onLoad, me); } } me.callParent(); }, * Lists will initially show a 'loading' item while the data is retrieved from the store. * In some cases the loaded data will result in a list that goes off the screen to the * right (as placement calculations were done with the loading item). This adapter will * allow show to be called with no arguments to show with the previous arguments and * thus recalculate the width and potentially hang the menu from the left. */ show : function () { var me = this; if (me.loadOnShow && !me.loaded && !me.store.loading) { me.store.load(); } me.callParent(); }, onLoad : function (store, records) { var me = this, gid, itemValue, i, len, listeners = { checkchange: me.checkChange, scope: me }; Ext.suspendLayouts(); me.removeAll(true); gid = me.single ? Ext.id() : null; for (i = 0, len = records.length; i < len; i++) { itemValue = records[i].get(me.idField); me.add(Ext.create('Ext.menu.CheckItem', { text: records[i].get(me.labelField), group: gid, checked: Ext.Array.contains(me.selected, itemValue), hideOnClick: false, value: itemValue, listeners: listeners })); } me.loaded = true; Ext.resumeLayouts(true); me.fireEvent('load', me, records); }, * Get the selected items. * @return {Array} selected */ getSelected : function () { return this.selected; }, setSelected : function (value) { value = this.selected = [].concat(value); if (this.loaded) { this.items.each(function(item){ item.setChecked(false, true); for (var i = 0, len = value.length; i < len; i++) { if (item.value == value[i]) { item.setChecked(true, true); } } }); } }, * Handler for the 'checkchange' event from an check item in this menu * @param {Object} item Ext.menu.CheckItem * @param {Object} checked The checked value that was set */ checkChange : function (item, checked) { var value = []; this.items.each(function(item){ if (item.checked) { value.push(item.value); } }); this.selected = value; this.fireEvent('checkchange', item, checked); } });