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