react-graph-grid 0.0.0 → 0.0.2
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/README.md +2 -15
- package/package.json +2 -2
- package/src/Dropdown.jsx +1 -1
- package/src/FieldEdit.jsx +374 -0
- package/src/Graph.jsx +34 -5
- package/src/Grid.jsx +13 -5
- package/src/GridDB.jsx +1 -1
- package/src/GridFE.jsx +509 -0
- package/src/GridFL.jsx +11 -1
- package/src/GridGR.jsx +13 -0
- package/src/Overlay.jsx +4 -2
- package/src/Tests/DebugApp.jsx +49 -2
- package/src/Tests/TestData.jsx +86 -683
- package/src/Themes/Images.jsx +1 -1
- package/src/Themes/Translate.jsx +1 -1
- package/src/main.jsx +3 -4
package/README.md
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
#
|
|
1
|
+
# react-graph-grid
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Currently, two official plugins are available:
|
|
6
|
-
|
|
7
|
-
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
|
8
|
-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
9
|
-
|
|
10
|
-
## React Compiler
|
|
11
|
-
|
|
12
|
-
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
|
13
|
-
|
|
14
|
-
## Expanding the ESLint configuration
|
|
15
|
-
|
|
16
|
-
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
|
3
|
+
A React package containing a grid that can communicate with other grids through a connection graph
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-graph-grid",
|
|
3
3
|
"author": "Mikhail Razumtsev",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "A React package containing a grid that can communicate with other grids through a connection graph",
|
|
5
5
|
"private": false,
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.2",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev": "vite --port 4000",
|
package/src/Dropdown.jsx
CHANGED
|
@@ -170,7 +170,7 @@ export class DropdownClass extends ModalClass {
|
|
|
170
170
|
style={{ listStyleType: 'none', display: 'flex', flexWrap: 'nowrap' }}
|
|
171
171
|
onClick={(e) => dd.onItemClick(e, 'append')}
|
|
172
172
|
>
|
|
173
|
-
${dd.translate('more...'
|
|
173
|
+
${dd.translate('more') + '...'}
|
|
174
174
|
</li>
|
|
175
175
|
</ul>
|
|
176
176
|
: <></>
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/* eslint-disable no-mixed-operators */
|
|
2
|
+
import { useState, useEffect, useRef, useLayoutEffect } from 'react';
|
|
3
|
+
import { BaseComponent } from './Base';
|
|
4
|
+
import { Modal } from './Modal';
|
|
5
|
+
import { Images } from './Themes/Images';
|
|
6
|
+
import { GridFE } from './GridFE';
|
|
7
|
+
export function FieldEdit(props) {
|
|
8
|
+
let fe = null;
|
|
9
|
+
|
|
10
|
+
const [feState, setState] = useState({ fe: fe, ind: 0 });
|
|
11
|
+
|
|
12
|
+
fe = feState.fe;
|
|
13
|
+
if (!fe) {
|
|
14
|
+
if (props.findFieldEdit) {
|
|
15
|
+
fe = props.findFieldEdit();
|
|
16
|
+
}
|
|
17
|
+
fe = fe || new FieldEditClass(props);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fe.textareaRef = useRef(null);
|
|
21
|
+
|
|
22
|
+
fe.column = props.column;
|
|
23
|
+
|
|
24
|
+
if (fe.value == null) {
|
|
25
|
+
fe.value = props.value || '';
|
|
26
|
+
fe.text = props.text || '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fe.getFilters = props.getFilters;
|
|
30
|
+
|
|
31
|
+
fe.multi = props.multi;
|
|
32
|
+
|
|
33
|
+
fe.id = props.keyPref || FieldEditClass._seq++;
|
|
34
|
+
|
|
35
|
+
fe.disabled = props.disabled;
|
|
36
|
+
|
|
37
|
+
BaseComponent.theme = BaseComponent.theme || {};
|
|
38
|
+
|
|
39
|
+
fe.buttonClass = props.buttonClass || BaseComponent.theme.filterButtonClass || '';
|
|
40
|
+
fe.inputClass = props.inputClass || BaseComponent.theme.inputClass || '';
|
|
41
|
+
fe.inputClassLG = props.inputClassLG || BaseComponent.theme.inputClassLG || '';
|
|
42
|
+
fe.clearButtonClass = props.clearButtonClass || BaseComponent.theme.clearButtonClass || '';
|
|
43
|
+
fe.selectClass = props.selectClass || BaseComponent.theme.selectClass || '';
|
|
44
|
+
fe.divContainerClass = props.divContainerClass || '';
|
|
45
|
+
|
|
46
|
+
fe.w = props.w;
|
|
47
|
+
fe.maxW = props.maxW;
|
|
48
|
+
fe.h = fe.h || props.h || '1.6em';
|
|
49
|
+
fe.textareaH = props.textareaH || '2.1em';
|
|
50
|
+
|
|
51
|
+
if (props.init) {
|
|
52
|
+
props.init(fe);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fe.refreshState = function () {
|
|
56
|
+
setState({ fe: fe, ind: fe.stateind++ });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
return () => {
|
|
61
|
+
if (fe._resizeObserver && fe._resizeObservedObj) {
|
|
62
|
+
fe._resizeObserver.unobserve(fe._resizeObservedObj);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}, [fe])
|
|
66
|
+
|
|
67
|
+
useLayoutEffect(() => {
|
|
68
|
+
if (fe.textareaRef.current && fe._refocus) {
|
|
69
|
+
fe.textareaRef.current.focus();
|
|
70
|
+
if (fe.selectionStart > 0) {
|
|
71
|
+
fe.textareaRef.current.setSelectionRange(fe.selectionStart, fe.selectionStart);
|
|
72
|
+
}
|
|
73
|
+
fe._refocus = false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const handleResize = () => {
|
|
77
|
+
//console.log('Textarea resized. New height:', fe.textareaRef.current.offsetHeight);
|
|
78
|
+
if (fe.textareaRef.current) {
|
|
79
|
+
fe.h = fe.textareaRef.current.offsetHeight;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (fe.textareaRef.current && fe._resizeObserved !== fe.textareaRef.current) {
|
|
84
|
+
fe._resizeObserver = new ResizeObserver(handleResize);
|
|
85
|
+
|
|
86
|
+
if (fe._resizeObservedObj) {
|
|
87
|
+
fe._resizeObserver.unobserve(fe._resizeObservedObj);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fe._resizeObservedObj = fe.textareaRef.current;
|
|
91
|
+
|
|
92
|
+
fe._resizeObserver.observe(fe.textareaRef.current);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return (fe.render());
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ==================================================================================================================================================================
|
|
100
|
+
export class FieldEditClass extends BaseComponent {
|
|
101
|
+
|
|
102
|
+
constructor(props) {
|
|
103
|
+
super(props);
|
|
104
|
+
|
|
105
|
+
const fe = this;
|
|
106
|
+
|
|
107
|
+
fe.stateind = 0;
|
|
108
|
+
fe.id = props.keyPref || FieldEditClass._seq++;
|
|
109
|
+
|
|
110
|
+
fe.onChange = props.onChange || (() => { });
|
|
111
|
+
|
|
112
|
+
fe.selectionStart = 0;
|
|
113
|
+
|
|
114
|
+
fe.large = props.large;
|
|
115
|
+
|
|
116
|
+
// просто разметка 'span 2' etc.
|
|
117
|
+
fe.gridColumn = props.gridColumn;
|
|
118
|
+
}
|
|
119
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
120
|
+
static _seq = 0;
|
|
121
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
122
|
+
render() {
|
|
123
|
+
const fe = this;
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<>
|
|
127
|
+
<div
|
|
128
|
+
key={`fieldEditDiv_${fe.id}_${fe.column.id}_`}
|
|
129
|
+
className={fe.divContainerClass ? fe.divContainerClass : fe.large ? 'field-edit' : fe.column.type === 'lookup' && !fe.column.readonly ? 'grid-cell-lookup' : 'grid-cell-edit'}
|
|
130
|
+
style={{
|
|
131
|
+
border: 'none',
|
|
132
|
+
height: !fe.inputClass ? fe.h : '',
|
|
133
|
+
width: '100%',
|
|
134
|
+
display: 'grid',
|
|
135
|
+
gridColumn: fe.gridColumn || '',
|
|
136
|
+
gridTemplateColumns: fe.getDivGridTemplateColumns(),
|
|
137
|
+
maxWidth: fe.maxW ? fe.maxW : '',
|
|
138
|
+
minHeight: fe.large ? '2.5em' : '',
|
|
139
|
+
columnGap: fe.large ? '0.2em' : '',
|
|
140
|
+
alignItems: 'center',
|
|
141
|
+
justifyItems: 'center',
|
|
142
|
+
}}
|
|
143
|
+
>
|
|
144
|
+
{
|
|
145
|
+
fe.renderInput()
|
|
146
|
+
}
|
|
147
|
+
{
|
|
148
|
+
fe.canClear() ?
|
|
149
|
+
<button
|
|
150
|
+
key={`fieldClearButton_${fe.id}_${fe.column.id}_`}
|
|
151
|
+
className={`${fe.large ? 'graph-filter-clear' : 'grid-cell-button'} ${fe.clearButtonClass || ''}`}
|
|
152
|
+
style={{ width: !fe.large ? '1.6em' : '', height: !fe.large ? '1.6em' : '' }}
|
|
153
|
+
onClick={(e) => {
|
|
154
|
+
fe.onClearClick(e);
|
|
155
|
+
}}
|
|
156
|
+
disabled={fe.disabled}
|
|
157
|
+
>
|
|
158
|
+
{!fe.large ? '×' : Images.images.filterClear()}
|
|
159
|
+
</button>
|
|
160
|
+
:
|
|
161
|
+
<></>
|
|
162
|
+
}
|
|
163
|
+
</div >
|
|
164
|
+
{
|
|
165
|
+
fe.lookupIsShowing ?
|
|
166
|
+
<Modal
|
|
167
|
+
title={fe.column.title}
|
|
168
|
+
renderContent={(wnd) => { return fe.renderLookupGrid(wnd); }}
|
|
169
|
+
pos={fe.popupPos}
|
|
170
|
+
onClose={(e) => {
|
|
171
|
+
if (fe.grid) {
|
|
172
|
+
delete fe.grid.value;
|
|
173
|
+
}
|
|
174
|
+
fe.closeLookupField();
|
|
175
|
+
fe.refreshState();
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
</Modal>
|
|
179
|
+
:
|
|
180
|
+
<></>
|
|
181
|
+
}
|
|
182
|
+
</>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
186
|
+
renderInput() {
|
|
187
|
+
const fe = this;
|
|
188
|
+
|
|
189
|
+
const isLookup = fe.column.type === 'lookup';
|
|
190
|
+
const noClear = !fe.canClear();
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<>
|
|
194
|
+
{
|
|
195
|
+
isLookup && !fe.column.readonly ?
|
|
196
|
+
<>
|
|
197
|
+
<input
|
|
198
|
+
key={`fieldLookupTitle_${fe.id}_${fe.column.id}_`}
|
|
199
|
+
style={{
|
|
200
|
+
width: '100%',
|
|
201
|
+
gridColumn: noClear ? 'span 2' : 'span 1',
|
|
202
|
+
overflowX: 'hidden',
|
|
203
|
+
height: !fe.large ? '1.7em' : '2.2em',
|
|
204
|
+
minHeight: !fe.inputClass ? fe.textareaH : fe.h,
|
|
205
|
+
boxSizing: 'border-box',
|
|
206
|
+
}}
|
|
207
|
+
disabled={true}
|
|
208
|
+
className={fe.large ? fe.inputClassLG : fe.inputClass || ''}
|
|
209
|
+
value={fe.value == null || fe.value == '' ? '' : fe.text != null && fe.text !== '' ? fe.text : fe.value}
|
|
210
|
+
>
|
|
211
|
+
</input>
|
|
212
|
+
<button
|
|
213
|
+
key={`fieldLookupButton_${fe.id}_${fe.column.id}_`}
|
|
214
|
+
className={`${fe.large ? 'graph-filter-button' : 'grid-cell-button'} ${fe.clearButtonClass}`}
|
|
215
|
+
style={{ width: !fe.large ? '1.6em' : '', height: !fe.large ? '1.6em' : '' }}
|
|
216
|
+
onClick={(e) => {
|
|
217
|
+
fe.openLookupField(e);
|
|
218
|
+
}}
|
|
219
|
+
disabled={fe.disabled}
|
|
220
|
+
>
|
|
221
|
+
{!fe.large ? '...' : Images.images.filterSelect()}
|
|
222
|
+
</button>
|
|
223
|
+
</>
|
|
224
|
+
:
|
|
225
|
+
<textarea
|
|
226
|
+
key={`fieldTextarea_${fe.id}_${fe.column.id}_`}
|
|
227
|
+
ref={fe.textareaRef}
|
|
228
|
+
className={`${fe.large ? fe.inputClassLG : fe.inputClass}`}
|
|
229
|
+
value={isLookup ? fe.text : fe.value || ''}
|
|
230
|
+
style={{
|
|
231
|
+
width: noClear ? 'calc(100% - 2px)' : '100%',
|
|
232
|
+
minHeight: !fe.inputClass ? fe.textareaH : fe.minH,
|
|
233
|
+
height: fe.h ? fe.h : !fe.large ? '1.7em' : '2.2em',
|
|
234
|
+
padding: '0',
|
|
235
|
+
boxSizing: 'border-box',
|
|
236
|
+
gridColumn: noClear ? 'span 3' : 'span 2',
|
|
237
|
+
resize: 'vertical',
|
|
238
|
+
overflowX: 'hidden',
|
|
239
|
+
}}
|
|
240
|
+
onChange={(e) => {
|
|
241
|
+
e.value = e.text = e.target.value;
|
|
242
|
+
fe.value = fe.text = e.target.value;
|
|
243
|
+
e.fe = fe;
|
|
244
|
+
|
|
245
|
+
fe.selectionStart = e.target.selectionStart;
|
|
246
|
+
fe._refocus = true;
|
|
247
|
+
|
|
248
|
+
fe.onChange(e);
|
|
249
|
+
fe.refreshState();
|
|
250
|
+
}}
|
|
251
|
+
disabled={fe.disabled || fe.column.readonly}
|
|
252
|
+
>
|
|
253
|
+
</textarea>
|
|
254
|
+
}
|
|
255
|
+
</>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
259
|
+
renderLookupGrid(wnd) {
|
|
260
|
+
const fe = this;
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<GridFE
|
|
264
|
+
getRows={fe.column.getRows}
|
|
265
|
+
keyField={fe.column.refKeyField}
|
|
266
|
+
nameField={fe.column.refNameField}
|
|
267
|
+
activeRow={fe.value}
|
|
268
|
+
multi={fe.multi}
|
|
269
|
+
level={fe.level + 1}
|
|
270
|
+
findGrid={() => { return fe.grid; }}
|
|
271
|
+
onSelectValue={(e) => {
|
|
272
|
+
fe._selectedOptions = e.values || [];
|
|
273
|
+
|
|
274
|
+
fe.value = e.value;
|
|
275
|
+
fe.text = e.text;
|
|
276
|
+
|
|
277
|
+
e.fe = fe;
|
|
278
|
+
|
|
279
|
+
fe.closeLookupField();
|
|
280
|
+
fe.onChange(e);
|
|
281
|
+
fe.refreshState();
|
|
282
|
+
}}
|
|
283
|
+
init={(lookupGrid) => {
|
|
284
|
+
if (!lookupGrid.value || fe.value && fe.value !== lookupGrid.value) {
|
|
285
|
+
fe.onLookupGridInit(lookupGrid);
|
|
286
|
+
|
|
287
|
+
delete lookupGrid._selectedRows;
|
|
288
|
+
if (fe.value) {
|
|
289
|
+
lookupGrid._selectedRowsDict = {};
|
|
290
|
+
for (let opt of fe._selectedOptions) {
|
|
291
|
+
let fakeRow = {};
|
|
292
|
+
fakeRow[fe.column.refKeyField] = opt.value;
|
|
293
|
+
fakeRow[fe.column.refNameField] = opt.label;
|
|
294
|
+
lookupGrid._selectedRowsDict[opt.value] = fakeRow;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
lookupGrid.closeSelfWnd = () => {
|
|
300
|
+
fe.closeLookupField();
|
|
301
|
+
fe.refreshState();
|
|
302
|
+
};
|
|
303
|
+
}}
|
|
304
|
+
onClose={() => {
|
|
305
|
+
fe.closeLookupField();
|
|
306
|
+
}}
|
|
307
|
+
>
|
|
308
|
+
</GridFE>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
312
|
+
getDivGridTemplateColumns() {
|
|
313
|
+
const fe = this;
|
|
314
|
+
return fe.large ? 'calc(100% - 4.6em) 2.2em 2.2em' : 'calc(100% - 2.8em) 1.4em 1.4em';
|
|
315
|
+
}
|
|
316
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
317
|
+
canClear() {
|
|
318
|
+
const fe = this;
|
|
319
|
+
return !fe.column.required && !fe.column.readonly && (fe.multi || fe.value != null && fe.value !== '');
|
|
320
|
+
}
|
|
321
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
322
|
+
onClearClick(e) {
|
|
323
|
+
const fe = this;
|
|
324
|
+
|
|
325
|
+
e.value = e.text = '';
|
|
326
|
+
fe.value = fe.text = '';
|
|
327
|
+
e.fe = fe;
|
|
328
|
+
fe.onChange(e);
|
|
329
|
+
fe.refreshState();
|
|
330
|
+
}
|
|
331
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
332
|
+
closeLookupField() {
|
|
333
|
+
const fe = this;
|
|
334
|
+
fe.lookupIsShowing = false;
|
|
335
|
+
if (fe.ownerGrid) {
|
|
336
|
+
fe.ownerGrid._clicksDisabled = false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
340
|
+
openLookupField(e) {
|
|
341
|
+
const fe = this;
|
|
342
|
+
|
|
343
|
+
const shift = (fe.level + 1) * 20;
|
|
344
|
+
|
|
345
|
+
fe.popupPos = fe.popupPos || { x: 100 + shift, y: 100 + shift, w: 1700, h: 900 };
|
|
346
|
+
|
|
347
|
+
fe.lookupIsShowing = true;
|
|
348
|
+
if (fe.ownerGrid) {
|
|
349
|
+
fe.ownerGrid._clicksDisabled = true;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
fe.refreshState();
|
|
353
|
+
}
|
|
354
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
355
|
+
onLookupGridInit(grid) {
|
|
356
|
+
const fe = this;
|
|
357
|
+
fe.grid = grid;
|
|
358
|
+
grid.value = fe.value;
|
|
359
|
+
grid.getSelectedRowIndex();
|
|
360
|
+
|
|
361
|
+
if (fe.getFilters) {
|
|
362
|
+
grid.collectFilters = fe.getFilters;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (grid._lookupPrepared) return;
|
|
366
|
+
|
|
367
|
+
grid._lookupPrepared = true;
|
|
368
|
+
|
|
369
|
+
grid.visible = true;
|
|
370
|
+
grid.title = fe.column.title;
|
|
371
|
+
grid.isSelecting = true;
|
|
372
|
+
};
|
|
373
|
+
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
374
|
+
}
|
package/src/Graph.jsx
CHANGED
|
@@ -128,9 +128,6 @@ export class GraphClass {
|
|
|
128
128
|
|
|
129
129
|
const graph = this;
|
|
130
130
|
|
|
131
|
-
// выставляем у графа признак "пущена волна"
|
|
132
|
-
graph._isMakingWave = true;
|
|
133
|
-
|
|
134
131
|
if (e.prepared == null) {
|
|
135
132
|
if (e.waveType == null) {
|
|
136
133
|
e.waveType = WaveType.value;
|
|
@@ -146,6 +143,9 @@ export class GraphClass {
|
|
|
146
143
|
e.prepared = true;
|
|
147
144
|
}
|
|
148
145
|
|
|
146
|
+
// выставляем у графа признак "пущена волна"
|
|
147
|
+
graph._isMakingWave = true;
|
|
148
|
+
|
|
149
149
|
// если запущена новая однотипная волна, то нет смысла продолжать текущую
|
|
150
150
|
if (graph.lastWaveInds[e.waveType] != null && e.waveInd < graph.lastWaveInds[e.waveType]) return;
|
|
151
151
|
|
|
@@ -163,13 +163,20 @@ export class GraphClass {
|
|
|
163
163
|
|
|
164
164
|
if (graph.lastWaveInds[e.waveType] == e.waveInd && e.nodes.length <= 0) {
|
|
165
165
|
graph._isMakingWave = false;
|
|
166
|
+
|
|
167
|
+
if (e.afterAllVisited) {
|
|
168
|
+
e.afterAllVisited();
|
|
169
|
+
}
|
|
166
170
|
return;
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
let i = 0;
|
|
170
174
|
while (i < e.nodes.length) {
|
|
171
175
|
let node = e.nodes[i];
|
|
172
|
-
node._lastWaveInd
|
|
176
|
+
if (node._lastWaveInd == e.waveInd) {
|
|
177
|
+
i++;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
173
180
|
|
|
174
181
|
// если текущий узел не должен посещаться текущей волной
|
|
175
182
|
if (node.skipOnWaveVisit && node.skipOnWaveVisit(e)) {
|
|
@@ -187,19 +194,41 @@ export class GraphClass {
|
|
|
187
194
|
node.visited = true;
|
|
188
195
|
}
|
|
189
196
|
|
|
190
|
-
e.
|
|
197
|
+
node._lastWaveInd = e.waveInd;
|
|
191
198
|
|
|
192
199
|
if (node.visitByWave) {
|
|
200
|
+
i++;
|
|
193
201
|
node.visitByWave(e).then(() => {
|
|
194
202
|
graph.addChildrenToWave([node], e);
|
|
195
203
|
|
|
204
|
+
const index = e.nodes.indexOf(node);
|
|
205
|
+
|
|
206
|
+
if (index > -1) {
|
|
207
|
+
e.nodes.splice(index, 1);
|
|
208
|
+
}
|
|
209
|
+
|
|
196
210
|
graph.triggerWave(e);
|
|
197
211
|
|
|
198
212
|
if (graph.lastWaveInds[e.waveType] == e.waveInd && e.nodes.length <= 0) {
|
|
199
213
|
graph._isMakingWave = false;
|
|
214
|
+
|
|
215
|
+
if (e.afterAllVisited) {
|
|
216
|
+
e.afterAllVisited();
|
|
217
|
+
}
|
|
200
218
|
}
|
|
201
219
|
});
|
|
202
220
|
}
|
|
221
|
+
else {
|
|
222
|
+
e.nodes.splice(i, 1);
|
|
223
|
+
|
|
224
|
+
if (graph.lastWaveInds[e.waveType] == e.waveInd && e.nodes.length <= 0) {
|
|
225
|
+
graph._isMakingWave = false;
|
|
226
|
+
|
|
227
|
+
if (e.afterAllVisited) {
|
|
228
|
+
e.afterAllVisited();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
203
232
|
}
|
|
204
233
|
}
|
|
205
234
|
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
package/src/Grid.jsx
CHANGED
|
@@ -85,7 +85,6 @@ export class GridClass extends BaseComponent {
|
|
|
85
85
|
grid.keyField = props.keyField;
|
|
86
86
|
grid.nameField = props.nameField;
|
|
87
87
|
|
|
88
|
-
//grid._selectedRowsDict = {};
|
|
89
88
|
if (props.renderCell) {
|
|
90
89
|
grid.defaultRenderCell = grid.renderCell;
|
|
91
90
|
grid.renderCell = props.renderCell;
|
|
@@ -164,6 +163,7 @@ export class GridClass extends BaseComponent {
|
|
|
164
163
|
rows => {
|
|
165
164
|
grid.rows = rows;
|
|
166
165
|
grid.afterGetRows();
|
|
166
|
+
grid._waitingRows = false;
|
|
167
167
|
grid.refreshState();
|
|
168
168
|
}
|
|
169
169
|
).finally(() => {
|
|
@@ -420,11 +420,19 @@ export class GridClass extends BaseComponent {
|
|
|
420
420
|
renderCell(grid, col, row) {
|
|
421
421
|
let val = row[col.name];
|
|
422
422
|
|
|
423
|
-
if (col.type === 'date' && val) {
|
|
424
|
-
|
|
423
|
+
if (col.type === 'date' && val != null) {
|
|
424
|
+
try {
|
|
425
|
+
val = grid.formatDate(val, grid.dateFormat);
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
}
|
|
425
429
|
}
|
|
426
|
-
else if (col.type === 'datetime' && val) {
|
|
427
|
-
|
|
430
|
+
else if (col.type === 'datetime' && val != null) {
|
|
431
|
+
try {
|
|
432
|
+
val = grid.formatDate(val, grid.dateTimeFormat);
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
}
|
|
428
436
|
}
|
|
429
437
|
|
|
430
438
|
if (col.allowVerticalResize) {
|
package/src/GridDB.jsx
CHANGED
|
@@ -690,7 +690,7 @@ export class GridDBClass extends GridPKClass {
|
|
|
690
690
|
// -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
691
691
|
setPocketImage() {
|
|
692
692
|
const grid = this;
|
|
693
|
-
if (!grid.multi) return;
|
|
693
|
+
if (!grid.multi || !grid.pagerButtonsDict) return;
|
|
694
694
|
|
|
695
695
|
const pocket = grid.pagerButtonsDict['pocket'];
|
|
696
696
|
if (!pocket) return;
|