/** * This component provides a grid holding selected items from a second store of potential * members. The `store` of this component represents the selected items. The "search store" * represents the potentially selected items. * * While this component is a grid and so you can configure `columns`, it is best to leave * that to this class in its `initComponent` method. That allows this class to create the * extra column that allows the user to remove rows. Instead use `{@link #fieldName}` and * `{@link #fieldTitle}` to configure the primary column's `dataIndex` and column `text`, * respectively. * * @since 5.0.0 */Ext.define('Ext.view.MultiSelector', { extend: 'Ext.grid.Panel', xtype: 'multiselector', config: { /** * @cfg {Object} search * This object configures the search popup component. By default this contains the * `xtype` for a `Ext.view.MultiSelectorSearch` component and specifies `autoLoad` * for its `store`. */ search: { xtype: 'multiselector-search', width: 200, height: 200, store: { autoLoad: true } } }, /** * @cfg {String} [fieldName="name"] * The name of the data field to display in the primary column of the grid. * @since 5.0.0 */ fieldName: 'name', /** * @cfg {String} [fieldTitle] * The text to display in the column header for the primary column of the grid. * @since 5.0.0 */ fieldTitle: null, /** * @cfg {String} removeRowText * The text to display in the "remove this row" column. By default this is a Unicode * "X" looking glyph. * @since 5.0.0 */ removeRowText: '\u2716', /** * @cfg {String} removeRowTip * The tooltip to display when the user hovers over the remove cell. * @since 5.0.0 */ removeRowTip: 'Remove this item', emptyText: 'Nothing selected', /** * @cfg {String} addToolText * The tooltip to display when the user hovers over the "+" tool in the panel header. * @since 5.0.0 */ addToolText: 'Search for items to add', initComponent: function () { var me = this, emptyText = me.emptyText, store = me.getStore(), search = me.getSearch(), fieldTitle = me.fieldTitle, searchStore, model; //<debug> if (!search) { Ext.Error.raise('The search configuration is required for the multi selector'); } //</debug> searchStore = search.store; if (searchStore.isStore) { model = searchStore.getModel(); } else { model = searchStore.model; } if (!store) { me.store = { model: model }; } if (emptyText && !me.viewConfig) { me.viewConfig = { deferEmptyText: false, emptyText: emptyText }; } if (!me.columns) { me.hideHeaders = !fieldTitle; me.columns = [ { text: fieldTitle, dataIndex: me.fieldName, flex: 1 }, me.makeRemoveRowColumn() ]; } me.callParent(); }, addTools: function () { this.addTool({ type: 'plus', tooltip: this.addToolText, callback: 'onShowSearch', scope: this }); }, convertSearchRecord: Ext.identityFn, convertSelectionRecord: Ext.identityFn, makeRemoveRowColumn: function () { var me = this; return { width: 22, menuDisabled: true, tdCls: Ext.baseCSSPrefix + 'multiselector-remove', processEvent: me.processRowEvent.bind(me), renderer: me.renderRemoveRow, updater: Ext.emptyFn, scope: me }; }, processRowEvent: function (type, view, cell, recordIndex, cellIndex, e, record, row) { if (e.type !== 'click') { return; } if (Ext.fly(cell).hasCls(Ext.baseCSSPrefix + 'multiselector-remove')) { this.store.remove(record); if (this.searchPopup) { this.searchPopup.deselectRecords(record); } } }, renderRemoveRow: function () { return '<span data-qtip="'+ this.removeRowTip + '" role="button">' + this.removeRowText + '</span>'; }, beforeDestroy: function() { Ext.un({ mousedown: 'onDismissSearch', scope: this }); this.callParent(); }, privates: { onDismissSearch: function (e) { var searchPopup = this.searchPopup; if (searchPopup && !(searchPopup.owns(e.getTarget()) || this.owns(e.getTarget()))) { Ext.un({ mousedown: 'onDismissSearch', scope: this }); searchPopup.hide(); } }, onShowSearch: function (panel, tool) { var me = this, searchPopup = me.searchPopup, store = me.getStore(); if (!searchPopup) { searchPopup = Ext.merge({ owner: me, field: me.fieldName, floating: true }, me.getSearch()); me.searchPopup = searchPopup = me.add(searchPopup); // If we were configured with records prior to the UI requesting the popup, // ensure that the records are selected in the popup. if (store.getCount()) { searchPopup.selectRecords(store.getRange()); } } searchPopup.showBy(me, 'tl-tr?'); Ext.on({ mousedown: 'onDismissSearch', scope: me }); } }});