react-graph-grid 0.1.9 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/GridFL.jsx ADDED
@@ -0,0 +1,468 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { BaseComponent } from './Base';
3
+ import { Images } from './Themes/Images';
4
+ import { GridDBClass } from './GridDB';
5
+ import { Dropdown } from './Dropdown';
6
+ // ==================================================================================================================================================================
7
+ export function GridFL(props) {
8
+ let grid = null;
9
+
10
+ const [gridState, setState] = useState({ grid: grid, ind: 0 });
11
+
12
+ grid = gridState.grid;
13
+ let needGetRows = false;
14
+ if (!grid || grid.uid !== props.uid && props.uid != null) {
15
+ grid = null;
16
+ if (props.findGrid) {
17
+ grid = props.findGrid(props);
18
+ }
19
+ grid = grid || new GridFLClass(props);
20
+ needGetRows = !props.noAutoRefresh && grid.hasVisibleParentGrids && !grid.hasVisibleParentGrids();
21
+ }
22
+
23
+ if (props.init) {
24
+ props.init(grid);
25
+ }
26
+
27
+ grid.refreshState = function () {
28
+ setState({ grid: grid, ind: grid.stateind++ });
29
+ }
30
+
31
+ grid._waitingRows = needGetRows && (grid.rows.length <= 0 || grid.columns.length <= 0);
32
+
33
+ useEffect(() => {
34
+ grid.setupEvents(grid);
35
+
36
+ if (grid._waitingRows) {
37
+
38
+ grid.getRows({ filters: grid.collectFilters(), grid: grid }).then(
39
+ rows => {
40
+ grid.rows = rows;
41
+ grid.afterGetRows();
42
+ grid.refreshState();
43
+ }
44
+ ).finally(() => {
45
+ grid._waitingRows = false;
46
+ grid.refreshState();
47
+ });
48
+ }
49
+ else if (grid.columns.length <= 0 && grid.getColumns) {
50
+ grid.prepareColumns().then(() => grid.refreshState());
51
+ }
52
+
53
+ return () => {
54
+ grid.clearEvents();
55
+ }
56
+ }, [grid])
57
+
58
+ return (grid.render());
59
+ }
60
+
61
+ // ==================================================================================================================================================================
62
+ export class GridFLClass extends GridDBClass {
63
+
64
+ constructor(props) {
65
+ super(props);
66
+
67
+ const grid = this;
68
+
69
+ grid.filtersDisabled = props.filtersDisabled;
70
+ grid.beforeOpen = props.beforeOpen;
71
+ }
72
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
73
+ render() {
74
+ const grid = this;
75
+
76
+ return (
77
+ <>
78
+ {super.render()}
79
+ <Dropdown
80
+ getItems={(e) => { return e.self._grid.getAutocomleteItems(e); }}
81
+ onItemClick={(e) => { e.self._grid.onAutocomleteItemClick(e); }}
82
+ closeWhenMiss={true}
83
+ init={(dd) => {
84
+ if (grid._autocompleteDropdown) {
85
+ dd.visible = grid._autocompleteDropdown.visible;
86
+ }
87
+ grid._autocompleteDropdown = dd;
88
+ dd._grid = grid;
89
+ if (grid._autocompleteRect) {
90
+ dd.opt.parentRect = grid._autocompleteRect;
91
+ }
92
+ }}
93
+ onClose={(e) => {
94
+ if (e.self._grid._inputingColumn) {
95
+ delete e.self._grid._inputingColumn;
96
+ if (e.self._grid.needRefresh()) {
97
+ e.self._grid.pageNumber = 1;
98
+ e.self._grid.selectedRowIndex = 0;
99
+ e.self._grid.refresh();
100
+ }
101
+ }
102
+ }}
103
+ >
104
+ </Dropdown>
105
+ </>
106
+ )
107
+ }
108
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
109
+ renderHeaderCell(col, context) {
110
+ const grid = this;
111
+ if (grid.filtersDisabled) {
112
+ return super.renderHeaderCell(col, context);
113
+ }
114
+
115
+ const hasFilter = col.filtrable && context !== 'fake' && col.filter != null && col.filter !== '';
116
+
117
+ const needFocus = grid._autoFocusColumn === col;
118
+ if (needFocus) {
119
+ delete grid._autoFocusColumn;
120
+ }
121
+
122
+ const isDisabled = grid._waitingRows || grid.isEditing() || grid.isDisabled();
123
+
124
+ return (
125
+ <>
126
+ {super.renderHeaderCell(col, context)}
127
+
128
+ {col.filtrable && context !== 'fake' ?
129
+ <>
130
+ <input
131
+ key={`colFilter_${grid.id}_${col.id}_`}
132
+ className={`grid-col-filter ${grid.opt.inputClass || BaseComponent.theme.inputClass || ''}`}
133
+ value={col.filter != null ? col.filter : ''}
134
+ title={col.filter != null ? col.filter : ''}
135
+ style={{ gridColumn: !hasFilter ? 'span 2' : '', width: 'calc(100% - 10px)' }}
136
+ grid-col-filter={`${grid.id}_${col.id}_`}
137
+ onChange={(e) => { grid.onColumnFilterChanging(col, e.target.value, e) }}
138
+ onClick={(e) => { grid.onColumnFilterClick(col, e); }}
139
+ onInput={(e) => { grid.onColumnFilterInput(col, e) }}
140
+ autoFocus={needFocus}
141
+ disabled={isDisabled ? 'disabled' : ''}
142
+ onBlur={(e) => { grid.onColumnFocusLost(col, col.filter, e); }}
143
+ autoComplete="off"
144
+ autocomplete="off"
145
+ >
146
+ </input>
147
+ {
148
+ <button
149
+ key={`colFilterClear_${grid.id}_${col.id}_`}
150
+ className={"grid-filter-clear"}
151
+ style={{ color: 'black', display: hasFilter ? 'flex' : 'none', justifyContent: 'center', alignItems: 'center', width: '8px' }}
152
+ type={'button'}
153
+ disabled={isDisabled ? 'disabled' : ''}
154
+ onClick={() => grid.clearColumnFilter(col)}
155
+ >×</button>
156
+ }
157
+ </>
158
+ :
159
+ <>
160
+ {/*context !== 'fake' ? <span className={grid.opt.inputClass || BaseComponent.theme.inputClass || ''}>&nbsp;</span> : <></>*/}
161
+ </>
162
+
163
+ }
164
+ </>
165
+ );
166
+ }
167
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
168
+ afterGetColumns() {
169
+ super.afterGetColumns();
170
+
171
+ const grid = this;
172
+ grid.hasColumnFilter = false;
173
+ for (let col of grid.columns) {
174
+ if (col.filtrable) {
175
+ grid.hasColumnFilter = true;
176
+ break;
177
+ }
178
+ }
179
+ }
180
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
181
+ getHeaderMinHeight() {
182
+ return !this.hasColumnFilter ? '1em' : '3em';
183
+ }
184
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
185
+ getAutocomleteItems() {
186
+ const grid = this;
187
+ return new Promise(function (resolve) {
188
+
189
+ grid.getRows({ filters: grid.collectFilters(true), grid: grid, autocompleteColumn: grid._inputingColumn }).then(
190
+ rows => {
191
+ const res = [];
192
+
193
+ if (grid._inputingColumn) {
194
+ let i = 0;
195
+ for (let row of rows) {
196
+ let txt = row[grid._inputingColumn.name] || String(row);
197
+
198
+ if (grid._inputingColumn.type === 'date') {
199
+ txt = grid.formatDate(txt, grid.dateFormat);
200
+ }
201
+ else if (grid._inputingColumn.type === 'datetime') {
202
+ txt = grid.formatDate(txt, grid.dateTimeFormat);
203
+ }
204
+
205
+ res.push({ id: i++, text: txt });
206
+ };
207
+ }
208
+
209
+ resolve(res);
210
+ }
211
+ );
212
+ });
213
+ }
214
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
215
+ collectFilters(noSaveFilterStr) {
216
+ const grid = this;
217
+ const filters = super.collectFilters();
218
+ const filterList = [];
219
+ let fo;
220
+
221
+ for (let col of grid.columns) {
222
+ if (!col.filtrable || col.filter == null || col.filter === '') continue;
223
+
224
+ fo = { type: 'column', filter: `${col.name} = ${col.filter}` };
225
+ filters.push(fo);
226
+
227
+ if (!noSaveFilterStr) {
228
+ filterList.push(fo.filter);
229
+ }
230
+ }
231
+
232
+ if (grid.beforeOpen != null && grid.beforeOpen !== '') {
233
+ fo = { type: 'graphLink', filter: grid.beforeOpen };
234
+ filters.push(fo);
235
+ }
236
+
237
+ if (!noSaveFilterStr) {
238
+ grid._lastFilters = filterList.join('&+&');
239
+ }
240
+ return filters;
241
+ }
242
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
243
+ showAutocomplete(e) {
244
+ const grid = this;
245
+
246
+ if (grid._waitingRows) return;
247
+
248
+ if (grid._autocompleteRect) {
249
+ grid._autocompleteDropdown.opt.parentRect = grid._autocompleteRect;
250
+ }
251
+
252
+ delete grid._autocompleteDropdown.maxW;
253
+ if (grid._inputingColumn && grid._inputingColumn.maxW) {
254
+ grid._autocompleteDropdown.maxW = +grid._inputingColumn.maxW;
255
+ }
256
+
257
+ grid._autocompleteDropdown.popup(e);
258
+
259
+ if (grid._autocompleteRect) {
260
+ delete grid._autocompleteRect;
261
+ }
262
+ }
263
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
264
+ needRefresh() {
265
+ const grid = this;
266
+ const prevFilterStr = grid._lastFilters;
267
+ grid.collectFilters();
268
+
269
+ return prevFilterStr !== grid._lastFilters;
270
+ }
271
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
272
+ onAutocomleteItemClick(e) {
273
+ const grid = this;
274
+
275
+ const item = grid._autocompleteDropdown.items.find(function (item) {
276
+ return String(item.id) === String(e.itemId);
277
+ });
278
+
279
+ if (!item) {
280
+ grid.log('onAutocomleteItemClick: ' + e.itemId + ' - does not found!');
281
+ return;
282
+ }
283
+
284
+ e.self.items = [];
285
+ grid._autocompleteDropdown.items = [];
286
+ grid._autocompleteDropdown.visible = false;
287
+
288
+ grid._autoFocusColumn = grid._inputingColumn;
289
+
290
+ //console.log('onAutocomleteItemClick : ' + grid._inputingColumn.filter);
291
+
292
+ grid._inputingColumn.filter = item.text;
293
+ if (e && e.target) {
294
+ grid._autocompleteRect = e.target.getBoundingClientRect();
295
+ }
296
+
297
+ if (grid.needRefresh()) {
298
+ grid.pageNumber = 1;
299
+ grid.selectedRowIndex = 0;
300
+ grid.refresh();
301
+ }
302
+ }
303
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
304
+ onColumnFilterChanging(column, filter, e) {
305
+ const grid = this;
306
+
307
+ //console.log('onColumnFilterChanging : ' + column.filter);
308
+
309
+ column.filter = filter;
310
+ if (e && e.target) {
311
+ grid._autocompleteRect = e.target.getBoundingClientRect();
312
+ }
313
+
314
+ grid._autocompleteDropdown.items = [];
315
+ grid.refreshState();
316
+ }
317
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
318
+ onColumnFocusLost(column, filter, e) {
319
+ const grid = this;
320
+ grid._waitingRows = true;
321
+
322
+ if (grid._inputingColumn !== column) {
323
+ //console.log('onColumnFocusLost: grid._inputingColumn !== column');
324
+ delete grid._inputingColumn;
325
+ }
326
+ if (e && e.target) {
327
+ grid._autocompleteRect = e.target.getBoundingClientRect();
328
+ }
329
+
330
+ setTimeout(() => {
331
+ if (grid.needRefresh()) {
332
+ //console.log('onColumnFocusLost : ' + column.filter);
333
+ grid._autocompleteDropdown.visible = false;
334
+ grid.pageNumber = 1;
335
+ grid.selectedRowIndex = 0;
336
+ grid.refresh();
337
+ }
338
+ else {
339
+ grid._waitingRows = false;
340
+ }
341
+ }, 150);
342
+ }
343
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
344
+ onColumnFilterClick(col, e) {
345
+ const grid = this;
346
+
347
+ if (grid._waitingRows) return;
348
+
349
+ grid._inputingColumn = col;
350
+ e.target.focus();
351
+ setTimeout(() => {
352
+ grid._autocompleteDropdown.items = [];
353
+ grid._autocompleteRect = e.target.getBoundingClientRect();
354
+
355
+ grid.showAutocomplete(e);
356
+ }, 150);
357
+ }
358
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
359
+ onColumnFilterInput(col, e) {
360
+ const grid = this;
361
+
362
+ grid._autocompleteSeq = grid._autocompleteSeq || 0;
363
+ let prevSeq = grid._autocompleteSeq;
364
+ grid._autocompleteSeq++;
365
+
366
+ col.filter = e.target.value;
367
+ grid._autoFocusColumn = col;
368
+
369
+ setTimeout(() => {
370
+ if (++prevSeq !== grid._autocompleteSeq) return;
371
+
372
+ grid._inputingColumn = col;
373
+ grid._autocompleteDropdown.items = [];
374
+
375
+ const elem = document.getElementById(e.target.id);
376
+
377
+ grid._autocompleteRect = elem ? elem.getBoundingClientRect() : e.target.getBoundingClientRect();
378
+
379
+ grid.showAutocomplete(e);
380
+ }, 100);
381
+ }
382
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
383
+ clearColumnFilter(column) {
384
+ const grid = this;
385
+
386
+ column.filter = '';
387
+
388
+ grid.pageNumber = 1;
389
+ grid.selectedRowIndex = 0;
390
+ grid.refresh();
391
+ }
392
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
393
+ clearAllColumnFilters() {
394
+ const grid = this;
395
+
396
+ for (let col of grid.columns) {
397
+ col.filter = '';
398
+ }
399
+
400
+ grid.pageNumber = 1;
401
+ grid.selectedRowIndex = 0;
402
+ grid.refresh();
403
+ }
404
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
405
+ isFiltered() {
406
+ const grid = this;
407
+
408
+ for (let col of grid.columns) {
409
+ if (col.filter) return true;
410
+ }
411
+
412
+ return false;
413
+ }
414
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
415
+ getHeaderGridTemplateColumns(col) {
416
+ return col.sortInd == null ? 'auto 16px' : 'auto 22px';
417
+ }
418
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
419
+ getGridSettingsList() {
420
+ const res = super.getGridSettingsList();
421
+
422
+ const grid = this;
423
+ if (!grid.filtersDisabled) {
424
+ res.push({ id: 3, text: grid.translate('Clear all filters', 'grid-menu') });
425
+ }
426
+
427
+ return res;
428
+ }
429
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
430
+ onSettingsItemClick(itemId) {
431
+ super.onSettingsItemClick(itemId);
432
+ const grid = this;
433
+
434
+ switch (String(itemId)) {
435
+ case '3':
436
+ grid.clearAllColumnFilters();
437
+ break;
438
+ default:
439
+ }
440
+ }
441
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
442
+ setupPagerButtons() {
443
+ const grid = this;
444
+ if (grid.pagerButtons && grid.pagerButtons.length > 0) return;
445
+
446
+ super.setupPagerButtons();
447
+
448
+ const clear = {
449
+ id: 10,
450
+ name: 'clear',
451
+ title: 'Clear all filters',
452
+ label: Images.images.clear ? '' : 'Clear',
453
+ click: () => {
454
+ grid.clearAllColumnFilters();
455
+ },
456
+ getDisabled: () => {
457
+ return grid._waitingRows || !grid.isFiltered();
458
+ },
459
+ img: Images.images.clear,
460
+ class: grid.pagerButtonsClass,
461
+ }
462
+
463
+ grid.pagerButtons.unshift(clear);
464
+ grid.pagerButtonsDict[clear.id] = grid.pagerButtonsDict[clear.name] = clear;
465
+ }
466
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
467
+ }
468
+ // ==================================================================================================================================================================