]> git.proxmox.com Git - extjs.git/blob - extjs/classic/classic/src/view/MultiSelector.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / view / MultiSelector.js
1 /**
2 * This component provides a grid holding selected items from a second store of potential
3 * members. The `store` of this component represents the selected items. The "search store"
4 * represents the potentially selected items.
5 *
6 * While this component is a grid and so you can configure `columns`, it is best to leave
7 * that to this class in its `initComponent` method. That allows this class to create the
8 * extra column that allows the user to remove rows. Instead use `{@link #fieldName}` and
9 * `{@link #fieldTitle}` to configure the primary column's `dataIndex` and column `text`,
10 * respectively.
11 *
12 * @since 5.0.0
13 */
14 Ext.define('Ext.view.MultiSelector', {
15 extend: 'Ext.grid.Panel',
16
17 xtype: 'multiselector',
18
19 config: {
20 /**
21 * @cfg {Object} search
22 * This object configures the search popup component. By default this contains the
23 * `xtype` for a `Ext.view.MultiSelectorSearch` component and specifies `autoLoad`
24 * for its `store`.
25 */
26 search: {
27 xtype: 'multiselector-search',
28 width: 200,
29 height: 200,
30 store: {
31 autoLoad: true
32 }
33 }
34 },
35
36 /**
37 * @cfg {String} [fieldName="name"]
38 * The name of the data field to display in the primary column of the grid.
39 * @since 5.0.0
40 */
41 fieldName: 'name',
42
43 /**
44 * @cfg {String} [fieldTitle]
45 * The text to display in the column header for the primary column of the grid.
46 * @since 5.0.0
47 */
48 fieldTitle: null,
49
50 /**
51 * @cfg {String} removeRowText
52 * The text to display in the "remove this row" column. By default this is a Unicode
53 * "X" looking glyph.
54 * @since 5.0.0
55 */
56 removeRowText: '\u2716',
57
58 /**
59 * @cfg {String} removeRowTip
60 * The tooltip to display when the user hovers over the remove cell.
61 * @since 5.0.0
62 */
63 removeRowTip: 'Remove this item',
64
65 emptyText: 'Nothing selected',
66
67 /**
68 * @cfg {String} addToolText
69 * The tooltip to display when the user hovers over the "+" tool in the panel header.
70 * @since 5.0.0
71 */
72 addToolText: 'Search for items to add',
73
74 initComponent: function () {
75 var me = this,
76 emptyText = me.emptyText,
77 store = me.getStore(),
78 search = me.getSearch(),
79 fieldTitle = me.fieldTitle,
80 searchStore, model;
81
82 //<debug>
83 if (!search) {
84 Ext.raise('The search configuration is required for the multi selector');
85 }
86 //</debug>
87
88 searchStore = search.store;
89 if (searchStore.isStore) {
90 model = searchStore.getModel();
91 } else {
92 model = searchStore.model;
93 }
94
95 if (!store) {
96 me.store = {
97 model: model
98 };
99 }
100
101 if (emptyText && !me.viewConfig) {
102 me.viewConfig = {
103 deferEmptyText: false,
104 emptyText: emptyText
105 };
106 }
107
108 if (!me.columns) {
109 me.hideHeaders = !fieldTitle;
110 me.columns = [
111 { text: fieldTitle, dataIndex: me.fieldName, flex: 1 },
112 me.makeRemoveRowColumn()
113 ];
114 }
115
116 me.callParent();
117 },
118
119 addTools: function () {
120 this.addTool({
121 type: 'plus',
122 tooltip: this.addToolText,
123 callback: 'onShowSearch',
124 scope: this
125 });
126 },
127
128 convertSearchRecord: Ext.identityFn,
129
130 convertSelectionRecord: Ext.identityFn,
131
132 makeRemoveRowColumn: function () {
133 var me = this;
134
135 return {
136 width: 22,
137 menuDisabled: true,
138 tdCls: Ext.baseCSSPrefix + 'multiselector-remove',
139 processEvent: me.processRowEvent.bind(me),
140 renderer: me.renderRemoveRow,
141 updater: Ext.emptyFn,
142 scope: me
143 };
144 },
145
146 processRowEvent: function (type, view, cell, recordIndex, cellIndex, e, record, row) {
147 if (e.type !== 'click') {
148 return;
149 }
150
151 if (Ext.fly(cell).hasCls(Ext.baseCSSPrefix + 'multiselector-remove')) {
152 this.store.remove(record);
153 if (this.searchPopup) {
154 this.searchPopup.deselectRecords(record);
155 }
156 }
157 },
158
159 renderRemoveRow: function () {
160 return '<span data-qtip="'+ this.removeRowTip + '" role="button">' +
161 this.removeRowText + '</span>';
162 },
163
164 beforeDestroy: function() {
165 Ext.un({
166 mousedown: 'onDismissSearch',
167 scope: this
168 });
169 this.callParent();
170 },
171
172 privates: {
173 onDismissSearch: function (e) {
174 var searchPopup = this.searchPopup;
175
176 if (searchPopup && !(searchPopup.owns(e.getTarget()) || this.owns(e.getTarget()))) {
177 Ext.un({
178 mousedown: 'onDismissSearch',
179 scope: this
180 });
181 searchPopup.hide();
182 }
183 },
184
185 onShowSearch: function (panel, tool) {
186 var me = this,
187 searchPopup = me.searchPopup,
188 store = me.getStore();
189
190 if (!searchPopup) {
191 searchPopup = Ext.merge({
192 owner: me,
193 field: me.fieldName,
194 floating: true
195 }, me.getSearch());
196 me.searchPopup = searchPopup = me.add(searchPopup);
197
198 // If we were configured with records prior to the UI requesting the popup,
199 // ensure that the records are selected in the popup.
200 if (store.getCount()) {
201 searchPopup.selectRecords(store.getRange());
202 }
203 }
204
205 searchPopup.showBy(me, 'tl-tr?');
206 Ext.on({
207 mousedown: 'onDismissSearch',
208 scope: me
209 });
210 }
211 }
212 });