react-graph-grid 0.0.0

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,456 @@
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 && !props.parentGrids;
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 grid.getAutocomleteItems(e); }}
81
+ onItemClick={(e) => { grid.onAutocomleteItemClick(e); }}
82
+ init={(dd) => {
83
+ if (grid._autocompleteDropdown) {
84
+ dd.visible = grid._autocompleteDropdown.visible;
85
+ }
86
+ grid._autocompleteDropdown = dd;
87
+ if (grid._autocompleteRect) {
88
+ dd.opt.parentRect = grid._autocompleteRect;
89
+ }
90
+ }}
91
+ onClose={() => {
92
+ if (grid._inputingColumn) {
93
+ delete grid._inputingColumn;
94
+ if (grid.needRefresh()) {
95
+ grid.pageNumber = 1;
96
+ grid.selectedRowIndex = 0;
97
+ grid.refresh();
98
+ }
99
+ }
100
+ }}
101
+ >
102
+ </Dropdown>
103
+ </>
104
+ )
105
+ }
106
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
107
+ renderHeaderCell(col, context) {
108
+ const grid = this;
109
+ if (grid.filtersDisabled) {
110
+ return super.renderHeaderCell(col, context);
111
+ }
112
+
113
+ const hasFilter = col.filtrable && context !== 'fake' && col.filter != null && col.filter !== '';
114
+
115
+ const needFocus = grid._autoFocusColumn === col;
116
+ if (needFocus) {
117
+ delete grid._autoFocusColumn;
118
+ }
119
+
120
+ const isDisabled = grid._waitingRows || grid.isEditing() || grid.isDisabled();
121
+
122
+ return (
123
+ <>
124
+ {super.renderHeaderCell(col, context)}
125
+
126
+ {col.filtrable && context !== 'fake' ?
127
+ <>
128
+ <input
129
+ key={`colFilter_${grid.id}_${col.id}_`}
130
+ className={`grid-col-filter ${grid.opt.inputClass || BaseComponent.theme.inputClass || ''}`}
131
+ value={col.filter != null ? col.filter : ''}
132
+ title={col.filter != null ? col.filter : ''}
133
+ style={{ gridColumn: !hasFilter ? 'span 2' : '', width: 'calc(100% - 10px)' }}
134
+ grid-col-filter={`${grid.id}_${col.id}_`}
135
+ onChange={(e) => { grid.onColumnFilterChanging(col, e.target.value, e) }}
136
+ onClick={(e) => { grid.onColumnFilterClick(col, e); }}
137
+ onInput={(e) => { grid.onColumnFilterInput(col, e) }}
138
+ autoFocus={needFocus}
139
+ disabled={isDisabled ? 'disabled' : ''}
140
+ onBlur={(e) => { grid.onColumnFocusLost(col, col.filter, e); }}
141
+ autoComplete="off"
142
+ >
143
+ </input>
144
+ {
145
+ <button
146
+ key={`colFilterClear_${grid.id}_${col.id}_`}
147
+ className={"grid-filter-clear"}
148
+ style={{ color: 'black', display: hasFilter ? 'flex' : 'none', justifyContent: 'center', alignItems: 'center', width: '8px' }}
149
+ type={'button'}
150
+ disabled={isDisabled ? 'disabled' : ''}
151
+ onClick={() => grid.clearColumnFilter(col)}
152
+ >×</button>
153
+ }
154
+ </>
155
+ :
156
+ <>
157
+ {/*context !== 'fake' ? <span className={grid.opt.inputClass || BaseComponent.theme.inputClass || ''}>&nbsp;</span> : <></>*/}
158
+ </>
159
+
160
+ }
161
+ </>
162
+ );
163
+ }
164
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
165
+ afterGetColumns() {
166
+ super.afterGetColumns();
167
+
168
+ const grid = this;
169
+ grid.hasColumnFilter = false;
170
+ for (let col of grid.columns) {
171
+ if (col.filtrable) {
172
+ grid.hasColumnFilter = true;
173
+ break;
174
+ }
175
+ }
176
+ }
177
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
178
+ getHeaderMinHeight() {
179
+ return !this.hasColumnFilter ? '1em' : '3em';
180
+ }
181
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
182
+ getAutocomleteItems() {
183
+ const grid = this;
184
+ return new Promise(function (resolve) {
185
+
186
+ grid.getRows({ filters: grid.collectFilters(true), grid: grid, autocompleteColumn: grid._inputingColumn }).then(
187
+ rows => {
188
+ const res = [];
189
+
190
+ if (grid._inputingColumn) {
191
+ let i = 0;
192
+ for (let row of rows) {
193
+ let txt = row[grid._inputingColumn.name] || String(row);
194
+
195
+ if (grid._inputingColumn.type === 'date') {
196
+ txt = grid.formatDate(txt, grid.dateFormat);
197
+ }
198
+ else if (grid._inputingColumn.type === 'datetime') {
199
+ txt = grid.formatDate(txt, grid.dateTimeFormat);
200
+ }
201
+
202
+ res.push({ id: i++, text: txt });
203
+ };
204
+ }
205
+
206
+ resolve(res);
207
+ }
208
+ );
209
+ });
210
+ }
211
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
212
+ collectFilters(noSaveFilterStr) {
213
+ const grid = this;
214
+ const filters = super.collectFilters();
215
+ const filterList = [];
216
+ let fo;
217
+
218
+ for (let col of grid.columns) {
219
+ if (!col.filtrable || col.filter == null || col.filter === '') continue;
220
+
221
+ fo = { type: 'column', filter: `${col.name} = ${col.filter}` };
222
+ filters.push(fo);
223
+
224
+ if (!noSaveFilterStr) {
225
+ filterList.push(fo.filter);
226
+ }
227
+ }
228
+
229
+ if (grid.beforeOpen != null && grid.beforeOpen !== '') {
230
+ fo = { type: 'graphLink', filter: grid.beforeOpen };
231
+ filters.push(fo);
232
+ }
233
+
234
+ if (!noSaveFilterStr) {
235
+ grid._lastFilters = filterList.join('&+&');
236
+ }
237
+ return filters;
238
+ }
239
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
240
+ showAutocomplete(e) {
241
+ const grid = this;
242
+
243
+ if (grid._autocompleteRect) {
244
+ grid._autocompleteDropdown.opt.parentRect = grid._autocompleteRect;
245
+ }
246
+
247
+ delete grid._autocompleteDropdown.maxW;
248
+ if (grid._inputingColumn && grid._inputingColumn.maxW) {
249
+ grid._autocompleteDropdown.maxW = +grid._inputingColumn.maxW;
250
+ }
251
+
252
+ grid._autocompleteDropdown.popup(e);
253
+
254
+ if (grid._autocompleteRect) {
255
+ delete grid._autocompleteRect;
256
+ }
257
+ }
258
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
259
+ needRefresh() {
260
+ const grid = this;
261
+ const prevFilterStr = grid._lastFilters;
262
+ grid.collectFilters();
263
+
264
+ return prevFilterStr !== grid._lastFilters;
265
+ }
266
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
267
+ onAutocomleteItemClick(e) {
268
+ const grid = this;
269
+
270
+ const item = grid._autocompleteDropdown.items.find(function (item) {
271
+ return String(item.id) === String(e.itemId);
272
+ });
273
+
274
+ if (!item) {
275
+ grid.log('onAutocomleteItemClick: ' + e.itemId + ' - does not found!');
276
+ return;
277
+ }
278
+
279
+ e.dropdown.items = [];
280
+ grid._autocompleteDropdown.items = [];
281
+ grid._autocompleteDropdown.visible = false;
282
+
283
+ grid._autoFocusColumn = grid._inputingColumn;
284
+
285
+ //console.log('onAutocomleteItemClick : ' + grid._inputingColumn.filter);
286
+
287
+ grid._inputingColumn.filter = item.text;
288
+ if (e && e.target) {
289
+ grid._autocompleteRect = e.target.getBoundingClientRect();
290
+ }
291
+
292
+ if (grid.needRefresh()) {
293
+ grid.pageNumber = 1;
294
+ grid.selectedRowIndex = 0;
295
+ grid.refresh();
296
+ }
297
+ }
298
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
299
+ onColumnFilterChanging(column, filter, e) {
300
+ const grid = this;
301
+
302
+ //console.log('onColumnFilterChanging : ' + column.filter);
303
+
304
+ column.filter = filter;
305
+ if (e && e.target) {
306
+ grid._autocompleteRect = e.target.getBoundingClientRect();
307
+ }
308
+
309
+ grid._autocompleteDropdown.items = [];
310
+ grid.refreshState();
311
+ }
312
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
313
+ onColumnFocusLost(column, filter, e) {
314
+ const grid = this;
315
+ if (grid._inputingColumn !== column) {
316
+ //console.log('onColumnFocusLost: grid._inputingColumn !== column');
317
+ delete grid._inputingColumn;
318
+ }
319
+ if (e && e.target) {
320
+ grid._autocompleteRect = e.target.getBoundingClientRect();
321
+ }
322
+
323
+ setTimeout(() => {
324
+ if (grid.needRefresh()) {
325
+ //console.log('onColumnFocusLost : ' + column.filter);
326
+ grid._autocompleteDropdown.visible = false;
327
+ grid.pageNumber = 1;
328
+ grid.selectedRowIndex = 0;
329
+ grid.refresh();
330
+ }
331
+ }, 150);
332
+ }
333
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
334
+ onColumnFilterClick(col, e) {
335
+ const grid = this;
336
+
337
+ grid._inputingColumn = col;
338
+ e.target.focus();
339
+ setTimeout(() => {
340
+ grid._autocompleteDropdown.items = [];
341
+ grid._autocompleteRect = e.target.getBoundingClientRect();
342
+
343
+ grid.showAutocomplete(e);
344
+ }, 150);
345
+ }
346
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
347
+ onColumnFilterInput(col, e) {
348
+ const grid = this;
349
+
350
+ grid._autocompleteSeq = grid._autocompleteSeq || 0;
351
+ let prevSeq = grid._autocompleteSeq;
352
+ grid._autocompleteSeq++;
353
+
354
+ col.filter = e.target.value;
355
+ grid._autoFocusColumn = col;
356
+
357
+ setTimeout(() => {
358
+ if (++prevSeq !== grid._autocompleteSeq) return;
359
+
360
+ grid._inputingColumn = col;
361
+ grid._autocompleteDropdown.items = [];
362
+
363
+ const elem = document.getElementById(e.target.id);
364
+
365
+ grid._autocompleteRect = elem ? elem.getBoundingClientRect() : e.target.getBoundingClientRect();
366
+
367
+ grid.showAutocomplete(e);
368
+ }, 100);
369
+ }
370
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
371
+ clearColumnFilter(column) {
372
+ const grid = this;
373
+
374
+ column.filter = '';
375
+
376
+ grid.pageNumber = 1;
377
+ grid.selectedRowIndex = 0;
378
+ grid.refresh();
379
+ }
380
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
381
+ clearAllColumnFilters() {
382
+ const grid = this;
383
+
384
+ for (let col of grid.columns) {
385
+ col.filter = '';
386
+ }
387
+
388
+ grid.pageNumber = 1;
389
+ grid.selectedRowIndex = 0;
390
+ grid.refresh();
391
+ }
392
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
393
+ isFiltered() {
394
+ const grid = this;
395
+
396
+ for (let col of grid.columns) {
397
+ if (col.filter) return true;
398
+ }
399
+
400
+ return false;
401
+ }
402
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
403
+ getHeaderGridTemplateColumns(col) {
404
+ return col.sortInd == null /*&& (col.filter == null || col.filter === '')*/ ? 'auto 18px' : 'auto 22px';
405
+ }
406
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
407
+ getGridSettingsList() {
408
+ const res = super.getGridSettingsList();
409
+
410
+ const grid = this;
411
+ if (!grid.filtersDisabled) {
412
+ res.push({ id: 3, text: grid.translate('Clear all filters', 'grid-menu') });
413
+ }
414
+
415
+ return res;
416
+ }
417
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
418
+ onSettingsItemClick(itemId) {
419
+ super.onSettingsItemClick(itemId);
420
+ const grid = this;
421
+
422
+ switch (String(itemId)) {
423
+ case '3':
424
+ grid.clearAllColumnFilters();
425
+ break;
426
+ default:
427
+ }
428
+ }
429
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
430
+ setupPagerButtons() {
431
+ const grid = this;
432
+ if (grid.pagerButtons && grid.pagerButtons.length > 0) return;
433
+
434
+ super.setupPagerButtons();
435
+
436
+ const clear = {
437
+ id: 10,
438
+ name: 'clear',
439
+ title: 'Clear all filters',
440
+ label: Images.images.clear ? '' : 'Clear',
441
+ click: () => {
442
+ grid.clearAllColumnFilters();
443
+ },
444
+ getDisabled: () => {
445
+ return grid._waitingRows || !grid.isFiltered();
446
+ },
447
+ img: Images.images.clear,
448
+ class: grid.pagerButtonsClass,
449
+ }
450
+
451
+ grid.pagerButtons.unshift(clear);
452
+ grid.pagerButtonsDict[clear.id] = grid.pagerButtonsDict[clear.name] = clear;
453
+ }
454
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
455
+ }
456
+ // ==================================================================================================================================================================