]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/form/GlobalSearchField.js
ui: eslint: fix various spacing related issues
[pve-manager.git] / www / manager6 / form / GlobalSearchField.js
CommitLineData
18532680
DC
1/*
2 * This is a global search field
3 * it loads the /cluster/resources on focus
4 * and displays the result in a floating grid
5 *
6 * it filters and sorts the objects by the algorithm in
7 * the customFilter function
8 *
9 * also it does accept key up/down and enter for input
10 * and it opens to ctrl+shift+f and ctrl+space
11 */
12Ext.define('PVE.form.GlobalSearchField', {
13 extend: 'Ext.form.field.Text',
14 alias: 'widget.pveGlobalSearchField',
15
16 emptyText: gettext('Search'),
17 enableKeyEvents: true,
18 selectOnFocus: true,
19 padding: '0 5 0 5',
20
21 grid: {
22 xtype: 'gridpanel',
23 focusOnToFront: false,
24 floating: true,
e7ade592 25 emptyText: Proxmox.Utils.noneText,
18532680 26 width: 600,
b35f19a3 27 height: 400,
18532680
DC
28 scrollable: {
29 xtype: 'scroller',
30 y: true,
8058410f 31 x: false,
18532680
DC
32 },
33 store: {
34 model: 'PVEResources',
8058410f 35 proxy: {
56a353b9 36 type: 'proxmox',
f6710aac
TL
37 url: '/api2/extjs/cluster/resources',
38 },
18532680
DC
39 },
40 plugins: {
41 ptype: 'bufferedrenderer',
42 trailingBufferZone: 20,
f6710aac 43 leadingBufferZone: 20,
18532680
DC
44 },
45
46 hideMe: function() {
47 var me = this;
9f0b4e04
CE
48 if (typeof me.ctxMenu !== 'undefined' && me.ctxMenu.isVisible()) {
49 return;
50 }
18532680
DC
51 me.hasFocus = false;
52 if (!me.textfield.hasFocus) {
53 me.hide();
54 }
55 },
56
57 setFocus: function() {
58 var me = this;
59 me.hasFocus = true;
60 },
61
62 listeners: {
63 rowclick: function(grid, record) {
64 var me = this;
65 me.textfield.selectAndHide(record.id);
66 },
9f0b4e04
CE
67 itemcontextmenu: function(v, record, item, index, event) {
68 var me = this;
69 me.ctxMenu = PVE.Utils.createCmdMenu(v, record, item, index, event);
70 },
18532680
DC
71 /* because of lint */
72 focusleave: {
f6710aac 73 fn: 'hideMe',
18532680 74 },
f6710aac 75 focusenter: 'setFocus',
18532680
DC
76 },
77
78 columns: [
79 {
80 text: gettext('Type'),
81 dataIndex: 'type',
82 width: 100,
f6710aac 83 renderer: PVE.Utils.render_resource_type,
18532680
DC
84 },
85 {
86 text: gettext('Description'),
87 flex: 1,
f6710aac 88 dataIndex: 'text',
18532680
DC
89 },
90 {
91 text: gettext('Node'),
f6710aac 92 dataIndex: 'node',
18532680
DC
93 },
94 {
95 text: gettext('Pool'),
f6710aac
TL
96 dataIndex: 'pool',
97 },
98 ],
18532680
DC
99 },
100
101 customFilter: function(item) {
102 var me = this;
103 var match = 0;
104 var fieldArr = [];
f6710aac 105 var i, j, fields;
18532680
DC
106
107 // different types of objects have different fields to search
108 // for example, a node will never have a pool and vice versa
109 switch (item.data.type) {
110 case 'pool': fieldArr = ['type', 'pool', 'text']; break;
111 case 'node': fieldArr = ['type', 'node', 'text']; break;
112 case 'storage': fieldArr = ['type', 'pool', 'node', 'storage']; break;
113 default: fieldArr = ['name', 'type', 'node', 'pool', 'vmid'];
114 }
115 if (me.filterVal === '') {
116 item.data.relevance = 0;
117 return true;
118 }
119
120 // all text is case insensitive and each word is
121 // searched alone
122 // for every partial match, the row gets
123 // 1 match point, for every exact match
124 // it gets 2 points
125 //
126 // results gets sorted by points (descending)
127 fields = me.filterVal.split(/\s+/);
8058410f 128 for (i = 0; i < fieldArr.length; i++) {
18532680
DC
129 var v = item.data[fieldArr[i]];
130 if (v !== undefined) {
131 v = v.toString().toLowerCase();
8058410f 132 for (j = 0; j < fields.length; j++) {
18532680
DC
133 if (v.indexOf(fields[j]) !== -1) {
134 match++;
8058410f 135 if (v === fields[j]) {
18532680
DC
136 match++;
137 }
138 }
139 }
140 }
141 }
142 // give the row the 'relevance' value
143 item.data.relevance = match;
144 return (match > 0);
145 },
146
147 updateFilter: function(field, newValue, oldValue) {
148 var me = this;
149 // parse input and filter store,
150 // show grid
151 me.grid.store.filterVal = newValue.toLowerCase().trim();
152 me.grid.store.clearFilter(true);
153 me.grid.store.filterBy(me.customFilter);
154 me.grid.getSelectionModel().select(0);
155 },
156
157 selectAndHide: function(id) {
158 var me = this;
159 me.tree.selectById(id);
160 me.grid.hide();
161 me.setValue('');
162 me.blur();
163 },
164
165 onKey: function(field, e) {
166 var me = this;
167 var key = e.getKey();
168
8058410f 169 switch (key) {
18532680
DC
170 case Ext.event.Event.ENTER:
171 // go to first entry if there is one
172 if (me.grid.store.getCount() > 0) {
173 me.selectAndHide(me.grid.getSelection()[0].data.id);
174 }
175 break;
176 case Ext.event.Event.UP:
177 me.grid.getSelectionModel().selectPrevious();
178 break;
179 case Ext.event.Event.DOWN:
180 me.grid.getSelectionModel().selectNext();
181 break;
182 case Ext.event.Event.ESC:
183 me.grid.hide();
184 me.blur();
185 break;
186 }
187 },
188
189 loadValues: function(field) {
190 var me = this;
191 var records = [];
192
193 me.hasFocus = true;
194 me.grid.textfield = me;
195 me.grid.store.load();
196 me.grid.showBy(me, 'tl-bl');
197 },
198
199 hideGrid: function() {
200 var me = this;
201
202 me.hasFocus = false;
203 if (!me.grid.hasFocus) {
204 me.grid.hide();
205 }
206 },
207
208 listeners: {
209 change: {
210 fn: 'updateFilter',
f6710aac 211 buffer: 250,
18532680
DC
212 },
213 specialkey: 'onKey',
214 focusenter: 'loadValues',
215 focusleave: {
216 fn: 'hideGrid',
f6710aac
TL
217 delay: 100,
218 },
18532680
DC
219 },
220
221 toggleFocus: function() {
222 var me = this;
223 if (!me.hasFocus) {
224 me.focus();
225 } else {
226 me.blur();
227 }
228 },
229
230 initComponent: function() {
231 var me = this;
232
233 if (!me.tree) {
234 throw "no tree given";
235 }
236
237 me.grid = Ext.create(me.grid);
238
239 me.callParent();
240
18532680
DC
241 /*because shift is also a function*/
242 // bind ctrl+shift+f and ctrl+space
243 // to open/close the search
244 me.keymap = new Ext.KeyMap({
245 target: Ext.get(document),
246 binding: [{
8058410f 247 key: 'F',
18532680
DC
248 ctrl: true,
249 shift: true,
250 fn: me.toggleFocus,
f6710aac
TL
251 scope: me,
252 }, {
8058410f 253 key: ' ',
18532680
DC
254 ctrl: true,
255 fn: me.toggleFocus,
f6710aac
TL
256 scope: me,
257 }],
18532680
DC
258 });
259
260 // always select first item and
261 // sort by relevance after load
262 me.mon(me.grid.store, 'load', function() {
263 me.grid.getSelectionModel().select(0);
264 me.grid.store.sort({
265 property: 'relevance',
f6710aac 266 direction: 'DESC',
18532680
DC
267 });
268 });
f6710aac 269 },
18532680
DC
270
271});