/* * Note that this control will most likely remain as an example, and not as a core Ext form * control. However, the API will be changing in a future release and so should not yet be * treated as a final, stable API at this time. */ /** * A control that allows selection of between two Ext.ux.form.MultiSelect controls. */ Ext.define('Ext.ux.form.ItemSelector', { extend: 'Ext.ux.form.MultiSelect', alias: ['widget.itemselectorfield', 'widget.itemselector'], alternateClassName: ['Ext.ux.ItemSelector'], requires: [ 'Ext.button.Button', 'Ext.ux.form.MultiSelect' ], /** * @cfg {Boolean} [hideNavIcons=false] True to hide the navigation icons */ hideNavIcons:false, /** * @cfg {Array} buttons Defines the set of buttons that should be displayed in between the ItemSelector * fields. Defaults to ['top', 'up', 'add', 'remove', 'down', 'bottom']. These names are used * to build the button CSS class names, and to look up the button text labels in {@link #buttonsText}. * This can be overridden with a custom Array to change which buttons are displayed or their order. */ buttons: ['top', 'up', 'add', 'remove', 'down', 'bottom'], /** * @cfg {Object} buttonsText The tooltips for the {@link #buttons}. * Labels for buttons. */ buttonsText: { top: "Move to Top", up: "Move Up", add: "Add to Selected", remove: "Remove from Selected", down: "Move Down", bottom: "Move to Bottom" }, initComponent: function() { var me = this; me.ddGroup = me.id + '-dd'; me.callParent(); // bindStore must be called after the fromField has been created because // it copies records from our configured Store into the fromField's Store me.bindStore(me.store); }, createList: function(){ var me = this; return Ext.create('Ext.ux.form.MultiSelect', { submitValue: false, flex: 1, dragGroup: me.ddGroup, dropGroup: me.ddGroup, store: { model: me.store.model, data: [] }, displayField: me.displayField, disabled: me.disabled, listeners: { boundList: { scope: me, itemdblclick: me.onItemDblClick, drop: me.syncValue } } }); }, setupItems: function() { var me = this; me.fromField = me.createList(); me.toField = me.createList(); return { layout: { type: 'hbox', align: 'stretch' }, items: [ me.fromField, { xtype: 'container', margins: '0 4', width: 22, layout: { type: 'vbox', pack: 'center' }, items: me.createButtons() }, me.toField ] }; }, createButtons: function(){ var me = this, buttons = []; if (!me.hideNavIcons) { Ext.Array.forEach(me.buttons, function(name) { buttons.push({ xtype: 'button', tooltip: me.buttonsText[name], handler: me['on' + Ext.String.capitalize(name) + 'BtnClick'], cls: Ext.baseCSSPrefix + 'form-itemselector-btn', iconCls: Ext.baseCSSPrefix + 'form-itemselector-' + name, navBtn: true, scope: me, margin: '4 0 0 0' }); }); } return buttons; }, getSelections: function(list){ var store = list.getStore(), selections = list.getSelectionModel().getSelection(); return Ext.Array.sort(selections, function(a, b){ a = store.indexOf(a); b = store.indexOf(b); if (a < b) { return -1; } else if (a > b) { return 1; } return 0; }); }, onTopBtnClick : function() { var list = this.toField.boundList, store = list.getStore(), selected = this.getSelections(list); store.suspendEvents(); store.remove(selected, true); store.insert(0, selected); store.resumeEvents(); list.refresh(); this.syncValue(); list.getSelectionModel().select(selected); }, onBottomBtnClick : function() { var list = this.toField.boundList, store = list.getStore(), selected = this.getSelections(list); store.suspendEvents(); store.remove(selected, true); store.add(selected); store.resumeEvents(); list.refresh(); this.syncValue(); list.getSelectionModel().select(selected); }, onUpBtnClick : function() { var list = this.toField.boundList, store = list.getStore(), selected = this.getSelections(list), i = 0, len = selected.length, index = store.getCount(); // Find index of first selection for (; i < len; ++i) { index = Math.min(index, store.indexOf(selected[i])); } // If first selection is not at the top, move the whole lot up if (index > 0) { store.suspendEvents(); store.remove(selected, true); store.insert(index - 1, selected); store.resumeEvents(); list.refresh(); this.syncValue(); list.getSelectionModel().select(selected); } }, onDownBtnClick : function() { var list = this.toField.boundList, store = list.getStore(), selected = this.getSelections(list), i = 0, len = selected.length, index = 0; // Find index of last selection for (; i < len; ++i) { index = Math.max(index, store.indexOf(selected[i])); } // If last selection is not at the bottom, move the whole lot down if (index < store.getCount() - 1) { store.suspendEvents(); store.remove(selected, true); store.insert(index + 2 - len, selected); store.resumeEvents(); list.refresh(); this.syncValue(); list.getSelectionModel().select(selected); } }, onAddBtnClick : function() { var me = this, fromList = me.fromField.boundList, selected = this.getSelections(fromList); fromList.getStore().remove(selected); this.toField.boundList.getStore().add(selected); this.syncValue(); }, onRemoveBtnClick : function() { var me = this, toList = me.toField.boundList, selected = this.getSelections(toList); toList.getStore().remove(selected); this.fromField.boundList.getStore().add(selected); this.syncValue(); }, syncValue: function() { this.setValue(this.toField.store.getRange()); }, onItemDblClick: function(view, rec){ var me = this, from = me.fromField.store, to = me.toField.store, current, destination; if (view === me.fromField.boundList) { current = from; destination = to; } else { current = to; destination = from; } current.remove(rec); destination.add(rec); me.syncValue(); }, setValue: function(value){ var me = this, fromStore = me.fromField.store, toStore = me.toField.store, selected; // Wait for from store to be loaded if (!me.fromField.store.getCount()) { me.fromField.store.on({ load: Ext.Function.bind(me.setValue, me, [value]), single: true }); return; } value = me.setupValue(value); me.mixins.field.setValue.call(me, value); selected = me.getRecordsForValue(value); Ext.Array.forEach(toStore.getRange(), function(rec){ if (!Ext.Array.contains(selected, rec)) { // not in the selected group, remove it from the toStore toStore.remove(rec); fromStore.add(rec); } }); toStore.removeAll(); Ext.Array.forEach(selected, function(rec){ // In the from store, move it over if (fromStore.indexOf(rec) > -1) { fromStore.remove(rec); } toStore.add(rec); }); }, onBindStore: function(store, initial) { var me = this; if (me.fromField) { me.fromField.store.removeAll() me.toField.store.removeAll(); // Add everything to the from field as soon as the Store is loaded if (store.getCount()) { me.populateFromStore(store); } else { me.store.on('load', me.populateFromStore, me); } } }, populateFromStore: function(store) { this.fromField.store.add(store.getRange()); // setValue wait for the from Store to be loaded this.fromField.store.fireEvent('load', this.fromField.store); }, onEnable: function(){ var me = this; me.callParent(); me.fromField.enable(); me.toField.enable(); Ext.Array.forEach(me.query('[navBtn]'), function(btn){ btn.enable(); }); }, onDisable: function(){ var me = this; me.callParent(); me.fromField.disable(); me.toField.disable(); Ext.Array.forEach(me.query('[navBtn]'), function(btn){ btn.disable(); }); }, onDestroy: function(){ this.bindStore(null); this.callParent(); } });