]>
git.proxmox.com Git - extjs.git/blob - extjs/classic/classic/src/view/MultiSelector.js
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.
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`,
14 Ext
.define('Ext.view.MultiSelector', {
15 extend
: 'Ext.grid.Panel',
17 xtype
: 'multiselector',
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`
27 xtype
: 'multiselector-search',
37 * @cfg {String} [fieldName="name"]
38 * The name of the data field to display in the primary column of the grid.
44 * @cfg {String} [fieldTitle]
45 * The text to display in the column header for the primary column of the grid.
51 * @cfg {String} removeRowText
52 * The text to display in the "remove this row" column. By default this is a Unicode
56 removeRowText
: '\u2716',
59 * @cfg {String} removeRowTip
60 * The tooltip to display when the user hovers over the remove cell.
63 removeRowTip
: 'Remove this item',
65 emptyText
: 'Nothing selected',
68 * @cfg {String} addToolText
69 * The tooltip to display when the user hovers over the "+" tool in the panel header.
72 addToolText
: 'Search for items to add',
74 initComponent: function() {
76 emptyText
= me
.emptyText
,
77 store
= me
.getStore(),
78 search
= me
.getSearch(),
79 fieldTitle
= me
.fieldTitle
,
84 Ext
.raise('The search configuration is required for the multi selector');
88 searchStore
= search
.store
;
90 if (searchStore
.isStore
) {
91 model
= searchStore
.getModel();
94 model
= searchStore
.model
;
103 if (emptyText
&& !me
.viewConfig
) {
105 deferEmptyText
: false,
111 me
.hideHeaders
= !fieldTitle
;
113 { text
: fieldTitle
, dataIndex
: me
.fieldName
, flex
: 1 },
114 me
.makeRemoveRowColumn()
121 addTools: function() {
126 tooltip
: me
.addToolText
,
127 callback
: 'onShowSearch',
130 me
.searchTool
= me
.tools
[me
.tools
.length
- 1];
133 convertSearchRecord
: Ext
.identityFn
,
135 convertSelectionRecord
: Ext
.identityFn
,
137 makeRemoveRowColumn: function() {
144 tdCls
: Ext
.baseCSSPrefix
+ 'multiselector-remove',
145 processEvent
: me
.processRowEvent
.bind(me
),
146 renderer
: me
.renderRemoveRow
,
147 updater
: Ext
.emptyFn
,
152 processRowEvent: function(type
, view
, cell
, recordIndex
, cellIndex
, e
, record
, row
) {
153 var body
= Ext
.getBody();
155 if (e
.type
=== 'click' ||
156 (e
.type
=== 'keydown' && (e
.keyCode
=== e
.SPACE
|| e
.keyCode
=== e
.ENTER
))) {
157 // Deleting the focused row will momentarily focusLeave
158 // That would dismiss the popup, so disable that.
159 body
.suspendFocusEvents();
160 this.store
.remove(record
);
161 body
.resumeFocusEvents();
163 if (this.searchPopup
) {
164 this.searchPopup
.deselectRecords(record
);
169 renderRemoveRow: function() {
170 return '<span data-qtip="' + this.removeRowTip
+ '" role="button" tabIndex="0">' +
171 this.removeRowText
+ '</span>';
174 onFocusLeave: function(e
) {
175 this.onDismissSearch();
176 this.callParent([e
]);
179 afterComponentLayout: function(width
, height
, prevWidth
, prevHeight
) {
181 popup
= me
.searchPopup
;
183 me
.callParent([width
, height
, prevWidth
, prevHeight
]);
185 if (popup
&& popup
.isVisible()) {
186 popup
.showBy(me
, me
.popupAlign
);
191 popupAlign
: 'tl-tr?',
193 onGlobalScroll: function(scroller
) {
194 // Collapse if the scroll is anywhere but inside this selector or the popup
195 if (!this.owns(scroller
.getElement())) {
196 this.onDismissSearch();
200 onDismissSearch: function(e
) {
201 var searchPopup
= this.searchPopup
;
204 (!e
|| !(searchPopup
.owns(e
.getTarget()) || this.owns(e
.getTarget())))) {
205 this.scrollListeners
.destroy();
206 this.touchListeners
.destroy();
211 onShowSearch: function(panel
, tool
, event
) {
213 searchPopup
= me
.searchPopup
,
214 store
= me
.getStore();
217 searchPopup
= Ext
.merge({
223 me
.searchPopup
= searchPopup
= me
.add(searchPopup
);
225 // If we were configured with records prior to the UI requesting the popup,
226 // ensure that the records are selected in the popup.
227 if (store
.getCount()) {
228 searchPopup
.selectRecords(store
.getRange());
232 searchPopup
.invocationEvent
= event
;
233 searchPopup
.showBy(me
, me
.popupAlign
);
235 // It only autofocuses its defaultFocus target if it was hidden.
236 // If they're reactivating the show tool, they'll expect to focus the search.
237 if (!event
|| event
.pointerType
!== 'touch') {
238 searchPopup
.lookupReference('searchField').focus();
241 me
.scrollListeners
= Ext
.on({
242 scroll
: 'onGlobalScroll',
247 // Dismiss on touch outside this component tree.
248 // Because touch platforms do not focus document.body on touch
249 // so no focusleave would occur to trigger a collapse.
250 me
.touchListeners
= Ext
.getDoc().on({
251 // Do not translate on non-touch platforms.
252 // mousedown will blur the field.
254 touchstart
: me
.onDismissSearch
,