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/Grid.jsx ADDED
@@ -0,0 +1,875 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { renderToStaticMarkup } from 'react-dom/server';
3
+ import { BaseComponent, log } from './Base';
4
+ import { OverlayClass } from './Overlay';
5
+ // ==================================================================================================================================================================
6
+ export function Grid(props) {
7
+ let grid = null;
8
+
9
+ const [gridState, setState] = useState({ grid: grid, ind: 0 });
10
+
11
+ grid = gridState.grid;
12
+ let needGetRows = false;
13
+ if (!grid || grid.uid !== props.uid && props.uid != null) {
14
+ grid = null;
15
+ if (props.findGrid) {
16
+ grid = props.findGrid(props);
17
+ }
18
+ grid = grid || new GridClass(props);
19
+ needGetRows = !props.noAutoRefresh;
20
+ }
21
+
22
+ if (props.init) {
23
+ props.init(grid);
24
+ }
25
+
26
+ grid.opt.selectedRowClass = props.selectedRowClass || BaseComponent.theme.selectedRowClass || '';
27
+
28
+ //grid.log(` 0.1 ReactGrid(). state = ${grid.stateind}`);
29
+
30
+ grid.refreshState = function () {
31
+ //grid.log(` -------------- refreshState ${grid.stateind} --------------- `);
32
+ setState({ grid: grid, ind: grid.stateind++ });
33
+ }
34
+
35
+ grid._waitingRows = needGetRows && (grid.rows.length <= 0 || grid.columns.length <= 0);
36
+
37
+ useEffect(() => {
38
+ grid.setupEvents(grid);
39
+
40
+ if (grid._waitingRows) {
41
+
42
+ grid.getRows({ filters: grid.collectFilters(), grid: grid }).then(
43
+ rows => {
44
+ grid.rows = rows;
45
+ grid.afterGetRows();
46
+ grid.refreshState();
47
+ }
48
+ ).finally(() => {
49
+ grid._waitingRows = false;
50
+ grid.refreshState();
51
+ });
52
+ }
53
+ else if (grid.columns.length <= 0 && grid.getColumns) {
54
+ grid.prepareColumns().then(() => grid.refreshState());
55
+ }
56
+
57
+ return () => {
58
+ grid.clearEvents();
59
+ }
60
+ }, [grid])
61
+
62
+ return (grid.render());
63
+ }
64
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
65
+ export class GridClass extends BaseComponent {
66
+ constructor(props) {
67
+ super(props);
68
+
69
+ const grid = this;
70
+
71
+ grid.opt = { zInd: props.zInd || 1 };
72
+
73
+ grid.id = GridClass._seq++;
74
+
75
+ if (props.getRows) {
76
+ grid.getRows = props.getRows;
77
+ }
78
+
79
+ grid._waitingRows = true;
80
+
81
+ grid.getColumns = props.getColumns || grid.getColumns;
82
+
83
+ grid.selectedRowIndex = 0;
84
+
85
+ grid.keyField = props.keyField;
86
+ grid.nameField = props.nameField;
87
+
88
+ //grid._selectedRowsDict = {};
89
+ if (props.renderCell) {
90
+ grid.defaultRenderCell = grid.renderCell;
91
+ grid.renderCell = props.renderCell;
92
+ }
93
+
94
+ grid.dateFormat = props.dateFormat || 'dd.MM.yyyy';//'DD.MM.YYYY';
95
+ grid.dateTimeFormat = props.dateTimeFormat || 'dd.MM.yyyy HH:mm:ss';
96
+
97
+ grid.rows = [];
98
+ grid.columns = [];
99
+
100
+ grid.stateind = 0;
101
+
102
+ grid.frozenHeader = props.frozenHeader == null ? true : props.frozenHeader;
103
+ grid.opt.selectedRowClass = props.selectedRowClass || BaseComponent.theme.selectedRowClass || '';
104
+ }
105
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
106
+ static _seq = 0;
107
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
108
+ log(message, pref) {
109
+ const grid = this;
110
+ pref = pref || `grid#${grid.id}`;
111
+ log(`${pref} : ${message}`);
112
+ }
113
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
114
+ afterGetRowsEvents() {
115
+ const grid = this;
116
+ grid.calculatePagesCount();
117
+ grid.getSelectedRowIndex();
118
+ grid.onSelectedRowChanged({ grid: grid, prev: grid.selectedRowIndex, new: grid.selectedRowIndex, source: 'afterGetRows' });
119
+ }
120
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
121
+ afterGetRows() {
122
+ const grid = this;
123
+ grid._waitingRows = false;
124
+ grid.log(`afterGetRows(). rows = ${grid.rows.length}. state = ${grid.stateind}`);
125
+
126
+ if (grid.totalRows == null && grid.pageSize <= 0) {
127
+ grid.totalRows = grid.rows && grid.rows.length ? grid.rows.length : 0;
128
+ }
129
+
130
+ if (grid.columns.length <= 0) {
131
+ grid.prepareColumns().then(() => {
132
+ grid.afterGetRowsEvents();
133
+ grid.refreshState();
134
+ });
135
+ }
136
+ else {
137
+ grid.afterGetRowsEvents();
138
+ }
139
+ }
140
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
141
+ getSelectedRowIndex() {
142
+ const grid = this;
143
+ if (grid.selectedRowIndex == null || grid.selectedRowIndex < 0) {
144
+ grid.selectedRowIndex = 0;
145
+ }
146
+ }
147
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
148
+ setupEvents() {
149
+ const grid = this;
150
+ grid.clearEvents = function () { }
151
+ }
152
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
153
+ calculatePagesCount() {
154
+ const grid = this;
155
+ grid.pagesCount = (grid.totalRows / grid.pageSize | 0) + (grid.totalRows % grid.pageSize > 0 ? 1 : 0);
156
+ }
157
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
158
+ refresh() {
159
+ const grid = this;
160
+ grid._waitingRows = true;
161
+ grid.refreshState();
162
+
163
+ grid.getRows({ filters: grid.collectFilters(), grid: grid }).then(
164
+ rows => {
165
+ grid.rows = rows;
166
+ grid.afterGetRows();
167
+ grid.refreshState();
168
+ }
169
+ ).finally(() => {
170
+ grid._waitingRows = false;
171
+ grid.refreshState();
172
+ });
173
+ }
174
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
175
+ collectFilters() {
176
+ return [];
177
+ }
178
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
179
+ render() {
180
+ const grid = this;
181
+
182
+ grid.getGridWidth();
183
+
184
+ grid.log(`render(). rows = ${grid.rows.length}. columns = ${grid.columns.length}. state = ${grid.stateind}`);
185
+ log(' -------------------------------------------------------------------------------------------------------------------------------------- ');
186
+
187
+ return (
188
+ <div
189
+ key={`gridDiv_${grid.id}_`}
190
+ className="grid-div"
191
+ style={{ maxHeight: grid.getGridMaxHeight(), overflowY: grid.frozenHeader ? 'auto' : 'hidden' }}
192
+ >
193
+ <table
194
+ key={`grid_${grid.id}_`}
195
+ className={grid.opt.gridClass || BaseComponent.theme.gridClass || 'grid-default'}
196
+ style={{ width: grid._currW + "px", tableLayout: 'fixed' }}
197
+ >
198
+ {grid.renderHeader()}
199
+ {grid.renderBody()}
200
+ </table>
201
+ </div>
202
+ );
203
+ }
204
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
205
+ getGridMaxHeight() {
206
+ return this.frozenHeader ? '40vh' : '';
207
+ }
208
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
209
+ getGridWidth() {
210
+ const grid = this;
211
+ //if (grid._currW > 0) return grid._currW;
212
+
213
+ let w = 0;
214
+ for (let col of grid.columns) {
215
+ if (col.visible === false) continue;
216
+ w += col.w;
217
+ }
218
+
219
+ grid._currW = w;
220
+ return grid._currW;
221
+ }
222
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
223
+ keyAdd() {
224
+ return '';
225
+ }
226
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
227
+ keyCellAdd() {
228
+ const grid = this;
229
+ return grid.stateind;
230
+ }
231
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
232
+ getHeaderGridTemplateColumns() {
233
+ return 'auto 8px';
234
+ }
235
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
236
+ getHeaderMinHeight() {
237
+ return '1em';
238
+ }
239
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
240
+ renderHeader(columns, context) {
241
+ const grid = this;
242
+ columns = columns || grid.columns;
243
+
244
+ if (!columns) return '';
245
+
246
+ return (
247
+ <thead>
248
+ <tr
249
+ /*style={{ position: "sticky", top: 0 }}*/
250
+ >
251
+ {context !== 'fake' ? grid.renderSelectColumnHeader() : <></>}
252
+ {columns.map((col, ind) => {
253
+ return (
254
+ col.visible === false ? <></> :
255
+ <th
256
+ key={`headerCell_${grid.id}_${col.id}_${col.w}_${ind}_${grid.keyAdd()}_`}
257
+ grid-header={`${grid.id}_${col.id}_${col.w}_`}
258
+ className={`${grid.opt.columnClass ? grid.opt.columnClass : ''} grid-header-th`}
259
+ style={{
260
+ position: grid.frozenHeader ? "sticky" : "inherit",
261
+ top: grid.frozenHeader ? 0 : undefined,
262
+ zIndex: grid.frozenHeader ? 1 : undefined,
263
+ width: col.w + "px",
264
+ overflow: "hidden",
265
+ }}
266
+ onMouseDown={(e) => grid.mouseDownColumnDrag(e, col)}
267
+ onMouseEnter={(e) => grid.mouseOverColumnDrag(e, col)}
268
+ onMouseLeave={(e) => grid.mouseOutColumnDrag(e, col)}
269
+ >
270
+ <div
271
+ style={{ /*position: "sticky", top: 0,*/
272
+ /*width: col.w + "px",*/
273
+ overflow: "hidden",
274
+ verticalAlign: "top",
275
+ display: 'grid',
276
+ gridTemplateColumns: 'calc(100% - 6px) 6px',
277
+ /*marginRight: '-5px',*/
278
+ }}
279
+ disabled={grid._waitingRows || col.disabled ? 'disabled' : ''}
280
+ >
281
+
282
+ <div
283
+ className={`grid-header-div-default ${grid.opt.headerDivClass || 'grid-header-div'}`}
284
+ style={{
285
+ display: 'grid',
286
+ gridTemplateColumns: grid.getHeaderGridTemplateColumns(col),
287
+ alignItems: 'center', //'start',//
288
+ justifyItems: 'start',
289
+ gridTemplateRows: '1.5em auto',
290
+ gridAutoFlow: 'row',
291
+ width: 'calc(100% + 8px)',
292
+ }}
293
+ >
294
+ {grid.renderHeaderCell(col, context)}
295
+ </div>
296
+ <div //style={{ position: "absolute", right: "-6px", top: "-1px", cursor: "e-resize", height: "100%", width: "12px", zIndex: (grid.opt.zInd + 1) }}
297
+ grid-rsz-x={`${grid.id}_${col.id}`}
298
+ style={{
299
+ position: "relative",
300
+ minHeight: grid.getHeaderMinHeight(col),
301
+ cursor: "e-resize",
302
+ height: "100%",
303
+ /*width: "12px",*/
304
+ width: "6px",
305
+ left: "0px",
306
+ zIndex: (grid.opt.zInd + 1)
307
+ }}
308
+ onMouseDown={(e) => { e.detail === 2 ? grid.mouseResizerDoubleClick(e, col) : grid.mouseResizerClick(e, col) }}
309
+ >
310
+ </div>
311
+ </div>
312
+ </th>
313
+ );
314
+ })}
315
+ </tr>
316
+ </thead>
317
+ );
318
+ }
319
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
320
+ renderSelectColumnHeader() {
321
+ return <></>;
322
+ }
323
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
324
+ renderHeaderCell(col) {
325
+ return (this.translate(col.title || col.name));
326
+ }
327
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
328
+ renderBody() {
329
+ const grid = this;
330
+
331
+ if (grid._waitingRows || !grid.columns || !grid.rows) {
332
+ return (
333
+ <tbody>
334
+ {
335
+ grid.rows && grid.rows.length > 0 ?
336
+ grid.rows.map((row, rind) => {
337
+ return (
338
+ <tr key={`gridRowWait_${grid.id}_${rind}_`} className="grid-waiting" style={{ borderTop: "0", borderBottom: "0" }}>
339
+ {
340
+ <td colSpan={grid.columns ? grid.columns.length : 0} className="grid-waiting">
341
+ {rind === Math.min(Math.floor(grid.rows.length / 2), 10) ? grid.Spinner(grid.id, Math.min(Math.max(grid._currW, 100), window.innerWidth), window.innerWidth) : <span>&nbsp;</span>}
342
+ </td>
343
+ }
344
+ </tr>
345
+ );
346
+ })
347
+ :
348
+ <tr key={`gridRowWait_${grid.id}_0_`} >
349
+ {
350
+ <td colSpan={grid.columns ? grid.columns.length : 0} className="grid-waiting">
351
+ {grid.Spinner(grid.id, Math.min(Math.max(grid._currW, 100), window.innerWidth), window.innerWidth)}
352
+ </td>
353
+ }
354
+ </tr>
355
+ }
356
+ </tbody>
357
+ );
358
+ }
359
+
360
+ return (
361
+ <tbody>
362
+ {
363
+ grid.rows.map((row, rind) => {
364
+ let selected = grid.isRowSelected(row, rind);
365
+ return (
366
+ <tr
367
+ key={`gridRow_${grid.id}_${rind}_${row[grid.keyField]}_${grid.keyAdd()}_${grid.keyCellAdd(selected)}_`}
368
+ className={selected ? `grid-selected-row ${grid.opt.selectedRowClass || ''}` : ''}
369
+
370
+ onDoubleClick={(e) => {
371
+ if (!grid._clicksDisabled) grid.onRowDblClick(e, row);
372
+ e.stopPropagation();
373
+ }}
374
+ onClick={(e) => {
375
+ if (!grid._clicksDisabled) grid.onSelectGridRow(e);
376
+ e.stopPropagation();
377
+ }}
378
+ >
379
+ {grid.renderRow(row, rind, selected)}
380
+ </tr>
381
+ );
382
+ })
383
+ }
384
+ {
385
+ grid.renderAdditionalRows()
386
+ }
387
+ </tbody>
388
+ );
389
+ }
390
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
391
+ renderAdditionalRows() {
392
+ return <></>;
393
+ }
394
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
395
+ isRowSelected(row, rowInd) {
396
+ const grid = this;
397
+ return grid.selectedRowIndex === rowInd;
398
+ }
399
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
400
+ renderRow(row, rowInd, selected) {
401
+ const grid = this;
402
+ return (
403
+ <>
404
+ {
405
+ grid.columns.map((col, cind) => {
406
+ return (
407
+ col.visible === false ? <></> :
408
+ <td
409
+ key={`gridCell_${grid.id}_${rowInd}_${cind}_${grid.keyAdd()}_${row[grid.keyField]}_`}
410
+ >
411
+ {grid.renderCell(grid, col, row, selected)}
412
+ </td>
413
+ );
414
+ })
415
+ }
416
+ </>
417
+ )
418
+ }
419
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
420
+ renderCell(grid, col, row) {
421
+ let val = row[col.name];
422
+
423
+ if (col.type === 'date' && val) {
424
+ val = grid.formatDate(val, grid.dateFormat);
425
+ }
426
+ else if (col.type === 'datetime' && val) {
427
+ val = grid.formatDate(val, grid.dateTimeFormat);
428
+ }
429
+
430
+ if (col.allowVerticalResize) {
431
+ return (
432
+ <div style={{ display: 'flex' }}>
433
+ <textarea
434
+ key={`cellTextarea_${col.id}_`}
435
+ className={col.inputClass}
436
+ value={val != null ? val : ''}
437
+ style={{
438
+ width: 'calc(100% - 0px)',
439
+ minHeight: !col.inputClass ? col.textareaH : col.h,
440
+ height: '1.8em',
441
+ padding: '0',
442
+ boxSizing: 'border-box',
443
+ gridColumn: 'span 3',
444
+ resize: 'vertical',
445
+ overflow: 'hidden',
446
+ border: '0',
447
+ }}
448
+ readOnly={true}
449
+ >
450
+ </textarea>
451
+ </div>
452
+ );
453
+ }
454
+
455
+ return (<span className='grid-cell' style={{ display: 'block', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'clip' }}>{val != null ? val : ''}</span>);
456
+ }
457
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
458
+ getColumns() {
459
+ const grid = this;
460
+ const res = [];
461
+ grid.colDict = {};
462
+
463
+ for (let row of grid.rows) {
464
+ for (let key in row) {
465
+ if (grid.colDict[key]) continue;
466
+
467
+ const col = grid.getColumn(key);
468
+
469
+ grid.colDict[col.name] = col;
470
+ res.push(col);
471
+ }
472
+ }
473
+
474
+ return res;
475
+ }
476
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
477
+ getColumn(name) {
478
+ return { name: name };
479
+ }
480
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
481
+ getSortedString() {
482
+ }
483
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
484
+ afterGetColumns() {
485
+ const grid = this;
486
+ grid.columns = grid.columns || [];
487
+ grid.colDict = grid.colDict || {};
488
+
489
+ let id = 0;
490
+ for (let col of grid.columns) {
491
+ col.id = id++;
492
+ col.title = col.title || col.name;
493
+ col.w = col.initW = col.w || 100;
494
+ col.minW = col.minW || 50;
495
+ col.grid = grid;
496
+ grid.colDict[col.id] = grid.colDict[col.name] = grid.colDict[col.name.toLowerCase()] = col;
497
+ }
498
+
499
+ if (!grid.columnsDefaultOrder) {
500
+ grid.columnsDefaultOrder = [];
501
+ Object.assign(grid.columnsDefaultOrder, grid.columns);
502
+ }
503
+
504
+ grid.getSortedString();
505
+ delete grid._waitingColumns;
506
+ }
507
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
508
+ async prepareColumns() {
509
+ const grid = this;
510
+
511
+ if (grid._waitingColumns) return;
512
+
513
+ grid._waitingColumns = true;
514
+
515
+ if (grid.getColumns && (!grid.columns || grid.columns.length <= 0)) {
516
+ grid.columns = await grid.getColumns();
517
+ grid.afterGetColumns();
518
+ }
519
+ else {
520
+ grid.afterGetColumns();
521
+ }
522
+ }
523
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
524
+ resetColumnsOrderToDefault() {
525
+ const grid = this;
526
+ let columns = [];
527
+ Object.assign(columns, grid.columnsDefaultOrder);
528
+
529
+ grid.refreshState();
530
+ grid.columns = columns;
531
+ }
532
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
533
+ resetColumnsWidthsToDefault() {
534
+ const grid = this;
535
+ for (let col of grid.columns) {
536
+ if (col.w === col.initW) continue;
537
+
538
+ col.w = col.initW;
539
+ }
540
+ grid.refreshState();
541
+ }
542
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
543
+ onSelectedRowChanged() {
544
+ }
545
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
546
+ mouseDownColumnDrag(e, column) {
547
+ const grid = this;
548
+ if (grid.columns.length < 2) return;
549
+
550
+ if (e.target.tagName === 'INPUT' || e.target.hasAttribute('grid-rsz-x')) return;
551
+
552
+ const th = e.target.closest('TH');
553
+ if (!th || !th.hasAttribute('grid-header')) return;
554
+
555
+ grid._movingColumn = column;
556
+
557
+ let fakeGrid;
558
+ function drawMovingColumn(pageX) {
559
+ fakeGrid = fakeGrid || grid.addFakeGrid(e, column, th);
560
+
561
+ const x = pageX + 10;
562
+
563
+ fakeGrid.style.left = x + 'px';
564
+ }
565
+ function onMouseMove(ev) {
566
+ drawMovingColumn(ev.clientX);
567
+
568
+ grid._skipClickColumn = column;
569
+ }
570
+
571
+ document.addEventListener('mousemove', onMouseMove);
572
+ document.addEventListener('mouseup', onMouseUp);
573
+ function onMouseUp() {
574
+ //e.preventDefault();
575
+ document.removeEventListener('mousemove', onMouseMove);
576
+ document.removeEventListener('mouseup', onMouseUp);
577
+
578
+ if (fakeGrid) {
579
+ fakeGrid.remove();
580
+ }
581
+ grid.clearMovingClass(th);
582
+
583
+ if (grid._movingColumn && grid._targetColumn && grid._movingColumn !== grid._targetColumn) {
584
+
585
+ const newColumns = [];
586
+ for (let col of grid.columns) {
587
+ switch (col) {
588
+ case grid._movingColumn:
589
+ break;
590
+ case grid._targetColumn:
591
+ if (grid.columns.indexOf(grid._movingColumn) > grid.columns.indexOf(grid._targetColumn)) {
592
+ newColumns.push(grid._movingColumn);
593
+ newColumns.push(grid._targetColumn);
594
+ }
595
+ else {
596
+ newColumns.push(grid._targetColumn);
597
+ newColumns.push(grid._movingColumn);
598
+ }
599
+ break;
600
+ default:
601
+ newColumns.push(col);
602
+ break;
603
+ }
604
+ }
605
+ grid.columns = newColumns;
606
+ grid.afterDragColumn(column);
607
+ grid.refreshState();
608
+ }
609
+
610
+ delete grid._movingColumn;
611
+ delete grid._targetColumn;
612
+ };
613
+ };
614
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
615
+ addFakeGrid(e, column, th) {
616
+ const grid = this;
617
+ const rect = th.getBoundingClientRect();
618
+ const fakeGrid = document.createElement('table');
619
+
620
+ fakeGrid.className = grid.opt.gridClass || BaseComponent.theme.gridClass || 'grid-default';
621
+ fakeGrid.style = grid.opt.style || '';
622
+ fakeGrid.style.zIndex = ++OverlayClass._zInd || 1000;
623
+ fakeGrid.style.position = 'fixed';
624
+ fakeGrid.style.top = (e.offsetY || 0 + rect.top + 5) + 'px';
625
+ fakeGrid.style.width = rect.width + 'px';
626
+ fakeGrid.style.height = rect.height + 'px';
627
+
628
+ fakeGrid.innerHTML = renderToStaticMarkup(grid.renderHeader([column], 'fake'));
629
+
630
+ document.body.append(fakeGrid);
631
+ return fakeGrid;
632
+ }
633
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
634
+ clearMovingClass = function (th) {
635
+ if (th.classList.contains('grid-header-drag-over')) {
636
+ th.classList.remove('grid-header-drag-over');
637
+ }
638
+ }
639
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
640
+ mouseOverColumnDrag(e, column) {
641
+ const grid = this;
642
+ if (!grid._movingColumn || !grid.colDict) return;
643
+
644
+ const th = e.target.closest('TH');
645
+ if (!th || !th.hasAttribute('grid-header')) return;
646
+
647
+ grid._targetColumn = column;
648
+
649
+ th.classList.add('grid-header-drag-over');
650
+ }
651
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
652
+ mouseOutColumnDrag(e) {
653
+ const grid = this;
654
+ const th = e.target.closest('TH');
655
+ if (!th || !th.hasAttribute('grid-header')) return;
656
+
657
+ if (!grid._movingColumn) return;
658
+
659
+ grid.clearMovingClass(th);
660
+
661
+ delete grid._targetColumn;
662
+ }
663
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
664
+ onRowDblClick() {
665
+ }
666
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
667
+ async canLeaveRow() {
668
+ return true;
669
+ }
670
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
671
+ async onSelectGridRow(e) {
672
+ const grid = this;
673
+
674
+ const gridElement = e.target.closest('TABLE');
675
+ if (!gridElement) return;
676
+
677
+ const rows = gridElement.tBodies[0].rows;
678
+ const clickedRow = e.target.closest('TR');
679
+
680
+ const prevSelectedIndex = grid.selectedRowIndex;
681
+ const newSelectedIndex = clickedRow.rowIndex - 1;
682
+
683
+ if (newSelectedIndex === prevSelectedIndex) return;
684
+
685
+ const saved = await grid.canLeaveRow(prevSelectedIndex);
686
+
687
+ if (!saved) return;
688
+
689
+
690
+ const prevSelRow = rows[grid.selectedRowIndex];
691
+ if (prevSelRow) {
692
+ prevSelRow.classList.remove('grid-selected-row');
693
+ if (grid.opt.selectedRowClass) {
694
+ prevSelRow.classList.remove(grid.opt.selectedRowClass);
695
+ }
696
+ }
697
+
698
+ grid.selectedRowIndex = newSelectedIndex;
699
+ const newSelRow = rows[grid.selectedRowIndex];
700
+ newSelRow.classList.add(`grid-selected-row`);
701
+ if (grid.opt.selectedRowClass) {
702
+ newSelRow.classList.add(grid.opt.selectedRowClass);
703
+ }
704
+
705
+ grid.onSelectedRowChanged({ grid: grid, prev: prevSelectedIndex, new: grid.selectedRowIndex, source: 'rowClick' });
706
+ }
707
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
708
+ getKeyColumn() {
709
+ const grid = this;
710
+ if (grid.keyField) return grid.keyField;
711
+
712
+ if (!grid.columns || grid.columns.length <= 0) return '';
713
+
714
+ for (let col of grid.columns) {
715
+ if (col.name.toLowerCase() === 'id') {
716
+ grid.keyField = col.name;
717
+ break;
718
+ }
719
+ }
720
+
721
+ grid.keyField = grid.keyField || grid.columns[0].name;
722
+ return grid.keyField;
723
+ }
724
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
725
+ selectedRow() {
726
+ const grid = this;
727
+
728
+ if (grid.selectedRowIndex == null || !grid.rows || grid.rows.length <= 0 || grid.selectedRowIndex < 0 || grid.selectedRowIndex >= grid.rows.length) return;
729
+
730
+ return grid.rows[grid.selectedRowIndex];
731
+ }
732
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
733
+ selectedValue() {
734
+ const grid = this;
735
+
736
+ const keyColumn = grid.getKeyColumn();
737
+ const row = grid.selectedRow();
738
+
739
+ return row != null ? row[keyColumn] : '';
740
+ }
741
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
742
+ selectedText() {
743
+ const grid = this;
744
+ if (!grid.nameField) return '';
745
+
746
+ const row = grid.selectedRow();
747
+ return row != null ? row[grid.nameField] : '';
748
+ }
749
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
750
+ selectedValues() {
751
+ const grid = this;
752
+
753
+ const keyColumn = grid.getKeyColumn();
754
+ const row = grid.selectedRow();
755
+
756
+ return row != null ? [{ value: row[keyColumn], label: row[grid.nameField] }] : [];
757
+ }
758
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
759
+ mouseResizerDoubleClick(e, column) {
760
+ const grid = this;
761
+
762
+ const th = e.target.closest('TH');
763
+ if (!th || !th.hasAttribute('grid-header')) return;
764
+
765
+ const initW = parseInt(th.style.width);
766
+
767
+ const fakeDiv = document.createElement('div');
768
+ fakeDiv.className = 'grid-header-div-default ' + (grid.opt.headerDivClass || "grid-header-div");
769
+ fakeDiv.style.opacity = 0;
770
+ fakeDiv.style.position = 'fixed';
771
+ fakeDiv.innerHTML = renderToStaticMarkup(grid.renderHeaderCell(column, 'fake'));
772
+ document.body.append(fakeDiv);
773
+
774
+ let contentSize = Math.max(column.minW, parseInt(getComputedStyle(fakeDiv).width));
775
+
776
+ fakeDiv.className = '';
777
+
778
+ for (let row of grid.rows) {
779
+ fakeDiv.innerHTML = renderToStaticMarkup(grid.renderCell(grid, column, row, false));
780
+ contentSize = Math.max(contentSize, parseInt(getComputedStyle(fakeDiv).width));
781
+ }
782
+
783
+ if (column.maxW != null) {
784
+ contentSize = Math.min(contentSize, +column.maxW);
785
+ }
786
+
787
+ const newW = contentSize + 12;//Math.max(column.w, contentSize);
788
+
789
+ if (newW !== initW) {
790
+ grid._currW = grid._currW - column.w + newW;
791
+ column.w = newW;
792
+ grid.afterResizeColumn(column);
793
+ grid.refreshState();
794
+ }
795
+
796
+ fakeDiv.remove();
797
+ }
798
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
799
+ mouseResizerClick(e, column) {
800
+ const grid = this;
801
+ const th = e.target.closest('TH');
802
+ if (!th || !th.hasAttribute('grid-header')) return;
803
+
804
+ const gridElement = th.closest('TABLE');
805
+
806
+ const initW = parseInt(getComputedStyle(th).width);
807
+
808
+ const shiftX = e.pageX;
809
+
810
+ let otherColsW = grid._currW - column.w;
811
+
812
+ //const div = e.target.parentElement;
813
+
814
+ let resizing;
815
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
816
+ function resize(pageX) {
817
+ if (shiftX > 0) {
818
+ let w = initW + pageX - shiftX;
819
+
820
+ const prevW = column.w;
821
+ column.w = (!column.maxW || w <= column.maxW) && (!column.minW || w >= column.minW) ? w : column.w;
822
+
823
+ if (column.w !== prevW) {
824
+ grid._currW = otherColsW + column.w;
825
+
826
+ gridElement.style.width = '';
827
+
828
+ th.style.width = column.w + 'px';
829
+ //div.style.width = column.w + 'px';
830
+
831
+ gridElement.style.width = grid._currW + 'px';
832
+ }
833
+ }
834
+ }
835
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
836
+ function onMouseMove(e) {
837
+ resizing = true;
838
+ resize(e.pageX);
839
+ }
840
+
841
+ const remDS = gridElement.ondragstart;
842
+ gridElement.ondragstart = function () {
843
+ return false;
844
+ };
845
+
846
+ const remSS = gridElement.onselectstart;
847
+ gridElement.onselectstart = function () {
848
+ return false;
849
+ };
850
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
851
+ function onMouseUp() {
852
+ document.removeEventListener('mousemove', onMouseMove);
853
+ document.removeEventListener('mouseup', onMouseUp);
854
+
855
+ gridElement.ondragstart = remDS;
856
+ gridElement.onselectstart = remSS;
857
+
858
+ if (resizing) {
859
+ resizing = false;
860
+ if (initW !== column.w) {
861
+ grid.afterResizeColumn(column);
862
+ grid.refreshState();
863
+ }
864
+ }
865
+ }
866
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
867
+ document.addEventListener('mousemove', onMouseMove);
868
+ document.addEventListener('mouseup', onMouseUp);
869
+ }
870
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
871
+ afterResizeColumn() { }
872
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
873
+ afterDragColumn() { }
874
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
875
+ }