canvasframework 0.3.6
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 +554 -0
- package/components/Accordion.js +252 -0
- package/components/AndroidDatePickerDialog.js +398 -0
- package/components/AppBar.js +225 -0
- package/components/Avatar.js +202 -0
- package/components/BottomNavigationBar.js +205 -0
- package/components/BottomSheet.js +374 -0
- package/components/Button.js +225 -0
- package/components/Card.js +193 -0
- package/components/Checkbox.js +180 -0
- package/components/Chip.js +212 -0
- package/components/CircularProgress.js +143 -0
- package/components/ContextMenu.js +116 -0
- package/components/DatePicker.js +257 -0
- package/components/Dialog.js +367 -0
- package/components/Divider.js +125 -0
- package/components/Drawer.js +261 -0
- package/components/FAB.js +270 -0
- package/components/FileUpload.js +315 -0
- package/components/IOSDatePickerWheel.js +268 -0
- package/components/ImageCarousel.js +193 -0
- package/components/ImageComponent.js +223 -0
- package/components/Input.js +309 -0
- package/components/List.js +94 -0
- package/components/ListItem.js +223 -0
- package/components/Modal.js +364 -0
- package/components/MultiSelectDialog.js +206 -0
- package/components/NumberInput.js +271 -0
- package/components/ProgressBar.js +88 -0
- package/components/RadioButton.js +142 -0
- package/components/SearchInput.js +315 -0
- package/components/SegmentedControl.js +202 -0
- package/components/Select.js +199 -0
- package/components/SelectDialog.js +255 -0
- package/components/Slider.js +113 -0
- package/components/Snackbar.js +243 -0
- package/components/Stepper.js +281 -0
- package/components/SwipeableListItem.js +179 -0
- package/components/Switch.js +147 -0
- package/components/Table.js +492 -0
- package/components/Tabs.js +125 -0
- package/components/Text.js +141 -0
- package/components/TextField.js +331 -0
- package/components/Toast.js +236 -0
- package/components/TreeView.js +420 -0
- package/components/Video.js +397 -0
- package/components/View.js +140 -0
- package/components/VirtualList.js +120 -0
- package/core/CanvasFramework.js +1271 -0
- package/core/CanvasWork.js +32 -0
- package/core/Component.js +153 -0
- package/core/LogicWorker.js +25 -0
- package/core/WebGLCanvasAdapter.js +1369 -0
- package/features/Column.js +43 -0
- package/features/Grid.js +47 -0
- package/features/LayoutComponent.js +43 -0
- package/features/OpenStreetMap.js +310 -0
- package/features/Positioned.js +33 -0
- package/features/PullToRefresh.js +328 -0
- package/features/Row.js +40 -0
- package/features/SignaturePad.js +257 -0
- package/features/Skeleton.js +84 -0
- package/features/Stack.js +21 -0
- package/index.js +101 -0
- package/manager/AccessibilityManager.js +107 -0
- package/manager/ErrorHandler.js +59 -0
- package/manager/FeatureFlags.js +60 -0
- package/manager/MemoryManager.js +107 -0
- package/manager/PerformanceMonitor.js +84 -0
- package/manager/SecurityManager.js +54 -0
- package/package.json +28 -0
- package/utils/AnimationEngine.js +428 -0
- package/utils/DataStore.js +403 -0
- package/utils/EventBus.js +407 -0
- package/utils/FetchClient.js +74 -0
- package/utils/FormValidator.js +355 -0
- package/utils/GeoLocationService.js +62 -0
- package/utils/I18n.js +207 -0
- package/utils/IndexedDBManager.js +273 -0
- package/utils/OfflineSyncManager.js +342 -0
- package/utils/QueryBuilder.js +478 -0
- package/utils/SafeArea.js +64 -0
- package/utils/SecureStorage.js +289 -0
- package/utils/StateManager.js +207 -0
- package/utils/WebSocketClient.js +66 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import Component from '../core/Component.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Arborescence pliable et sélectionnable
|
|
5
|
+
* @class
|
|
6
|
+
* @extends Component
|
|
7
|
+
* @property {Array} nodes - Nœuds de l'arbre
|
|
8
|
+
* @property {Set} expandedNodes - Nœuds dépliés
|
|
9
|
+
* @property {Object} selectedNode - Nœud sélectionné
|
|
10
|
+
* @property {number} indentSize - Taille de l'indentation
|
|
11
|
+
* @property {number} nodeHeight - Hauteur d'un nœud
|
|
12
|
+
* @property {boolean} showIcons - Afficher les icônes
|
|
13
|
+
* @property {string} expandIcon - Icône de dépliage
|
|
14
|
+
* @property {string} collapseIcon - Icône de repliage
|
|
15
|
+
* @property {Function} onNodeClick - Callback clic nœud
|
|
16
|
+
* @property {Function} onNodeExpand - Callback dépliage
|
|
17
|
+
*/
|
|
18
|
+
class TreeView extends Component {
|
|
19
|
+
/**
|
|
20
|
+
* Crée une instance de TreeView
|
|
21
|
+
* @param {CanvasFramework} framework - Framework parent
|
|
22
|
+
* @param {Object} [options={}] - Options de configuration
|
|
23
|
+
* @param {Array} [options.nodes=[]] - Nœuds [{id, label, children, icon}]
|
|
24
|
+
* @param {Array} [options.defaultExpanded=[]] - IDs des nœuds dépliés par défaut
|
|
25
|
+
* @param {number} [options.indentSize=24] - Taille indentation
|
|
26
|
+
* @param {number} [options.nodeHeight=40] - Hauteur nœud
|
|
27
|
+
* @param {boolean} [options.showIcons=true] - Afficher icônes
|
|
28
|
+
* @param {Function} [options.onNodeClick] - Callback clic
|
|
29
|
+
* @param {Function} [options.onNodeExpand] - Callback dépliage
|
|
30
|
+
*/
|
|
31
|
+
constructor(framework, options = {}) {
|
|
32
|
+
super(framework, options);
|
|
33
|
+
|
|
34
|
+
this.nodes = options.nodes || [];
|
|
35
|
+
this.expandedNodes = new Set(options.defaultExpanded || []);
|
|
36
|
+
this.selectedNode = null;
|
|
37
|
+
this.indentSize = options.indentSize || 24;
|
|
38
|
+
this.nodeHeight = options.nodeHeight || 40;
|
|
39
|
+
this.showIcons = options.showIcons !== false;
|
|
40
|
+
|
|
41
|
+
this.onNodeClick = options.onNodeClick || null;
|
|
42
|
+
this.onNodeExpand = options.onNodeExpand || null;
|
|
43
|
+
|
|
44
|
+
const platform = framework.platform;
|
|
45
|
+
|
|
46
|
+
// Styles selon la plateforme
|
|
47
|
+
if (platform === 'material') {
|
|
48
|
+
this.bgColor = '#FFFFFF';
|
|
49
|
+
this.hoverBg = 'rgba(0, 0, 0, 0.04)';
|
|
50
|
+
this.selectedBg = 'rgba(98, 0, 238, 0.08)';
|
|
51
|
+
this.textColor = '#000000';
|
|
52
|
+
this.iconColor = '#666666';
|
|
53
|
+
this.borderColor = 'rgba(0, 0, 0, 0.12)';
|
|
54
|
+
} else {
|
|
55
|
+
this.bgColor = '#FFFFFF';
|
|
56
|
+
this.hoverBg = 'rgba(0, 0, 0, 0.03)';
|
|
57
|
+
this.selectedBg = 'rgba(0, 122, 255, 0.1)';
|
|
58
|
+
this.textColor = '#000000';
|
|
59
|
+
this.iconColor = '#6C6C70';
|
|
60
|
+
this.borderColor = 'rgba(60, 60, 67, 0.29)';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Calculer la hauteur totale
|
|
64
|
+
this.updateHeight();
|
|
65
|
+
|
|
66
|
+
// État de hover
|
|
67
|
+
this.hoveredNode = null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Met à jour la hauteur du composant
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
updateHeight() {
|
|
75
|
+
const flattenedNodes = this.getFlattenedNodes();
|
|
76
|
+
this.height = flattenedNodes.length * this.nodeHeight;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Aplatit l'arbre en liste
|
|
81
|
+
* @param {Array} [nodes=this.nodes] - Nœuds à aplatir
|
|
82
|
+
* @param {number} [level=0] - Niveau de profondeur
|
|
83
|
+
* @returns {Array} Liste aplatie
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
getFlattenedNodes(nodes = this.nodes, level = 0) {
|
|
87
|
+
let result = [];
|
|
88
|
+
|
|
89
|
+
for (let node of nodes) {
|
|
90
|
+
result.push({ ...node, level });
|
|
91
|
+
|
|
92
|
+
if (node.children &&
|
|
93
|
+
node.children.length > 0 &&
|
|
94
|
+
this.expandedNodes.has(node.id)) {
|
|
95
|
+
result = result.concat(this.getFlattenedNodes(node.children, level + 1));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Toggle l'expansion d'un nœud
|
|
104
|
+
* @param {Object} node - Nœud à toggler
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
toggleNode(node) {
|
|
108
|
+
if (this.expandedNodes.has(node.id)) {
|
|
109
|
+
this.expandedNodes.delete(node.id);
|
|
110
|
+
} else {
|
|
111
|
+
this.expandedNodes.add(node.id);
|
|
112
|
+
if (this.onNodeExpand) {
|
|
113
|
+
this.onNodeExpand(node);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.updateHeight();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Sélectionne un nœud
|
|
121
|
+
* @param {Object} node - Nœud à sélectionner
|
|
122
|
+
* @private
|
|
123
|
+
*/
|
|
124
|
+
selectNode(node) {
|
|
125
|
+
this.selectedNode = node;
|
|
126
|
+
if (this.onNodeClick) {
|
|
127
|
+
this.onNodeClick(node);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Dessine le composant
|
|
133
|
+
* @param {CanvasRenderingContext2D} ctx - Contexte de dessin
|
|
134
|
+
*/
|
|
135
|
+
draw(ctx) {
|
|
136
|
+
ctx.save();
|
|
137
|
+
|
|
138
|
+
// Fond
|
|
139
|
+
ctx.fillStyle = this.bgColor;
|
|
140
|
+
ctx.fillRect(this.x, this.y, this.width, this.height);
|
|
141
|
+
|
|
142
|
+
// Bordure
|
|
143
|
+
ctx.strokeStyle = this.borderColor;
|
|
144
|
+
ctx.lineWidth = 1;
|
|
145
|
+
ctx.strokeRect(this.x, this.y, this.width, this.height);
|
|
146
|
+
|
|
147
|
+
// Dessiner les nœuds
|
|
148
|
+
const flattenedNodes = this.getFlattenedNodes();
|
|
149
|
+
flattenedNodes.forEach((node, index) => {
|
|
150
|
+
this.drawNode(ctx, node, index);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
ctx.restore();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Dessine un nœud
|
|
158
|
+
* @param {CanvasRenderingContext2D} ctx - Contexte de dessin
|
|
159
|
+
* @param {Object} node - Nœud à dessiner
|
|
160
|
+
* @param {number} index - Index du nœud
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
drawNode(ctx, node, index) {
|
|
164
|
+
const nodeY = this.y + (index * this.nodeHeight);
|
|
165
|
+
const indent = node.level * this.indentSize;
|
|
166
|
+
const hasChildren = node.children && node.children.length > 0;
|
|
167
|
+
const isExpanded = this.expandedNodes.has(node.id);
|
|
168
|
+
const isSelected = this.selectedNode && this.selectedNode.id === node.id;
|
|
169
|
+
const isHovered = this.hoveredNode && this.hoveredNode.id === node.id;
|
|
170
|
+
|
|
171
|
+
// Fond
|
|
172
|
+
if (isSelected) {
|
|
173
|
+
ctx.fillStyle = this.selectedBg;
|
|
174
|
+
ctx.fillRect(this.x, nodeY, this.width, this.nodeHeight);
|
|
175
|
+
} else if (isHovered) {
|
|
176
|
+
ctx.fillStyle = this.hoverBg;
|
|
177
|
+
ctx.fillRect(this.x, nodeY, this.width, this.nodeHeight);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Bordure inférieure
|
|
181
|
+
ctx.strokeStyle = this.borderColor;
|
|
182
|
+
ctx.lineWidth = 1;
|
|
183
|
+
ctx.beginPath();
|
|
184
|
+
ctx.moveTo(this.x, nodeY + this.nodeHeight);
|
|
185
|
+
ctx.lineTo(this.x + this.width, nodeY + this.nodeHeight);
|
|
186
|
+
ctx.stroke();
|
|
187
|
+
|
|
188
|
+
let currentX = this.x + 16 + indent;
|
|
189
|
+
|
|
190
|
+
// Icône expand/collapse
|
|
191
|
+
if (hasChildren) {
|
|
192
|
+
const iconSize = 16;
|
|
193
|
+
const iconX = currentX;
|
|
194
|
+
const iconY = nodeY + this.nodeHeight / 2;
|
|
195
|
+
|
|
196
|
+
ctx.strokeStyle = this.iconColor;
|
|
197
|
+
ctx.lineWidth = 2;
|
|
198
|
+
ctx.lineCap = 'round';
|
|
199
|
+
|
|
200
|
+
if (isExpanded) {
|
|
201
|
+
// Chevron down
|
|
202
|
+
ctx.beginPath();
|
|
203
|
+
ctx.moveTo(iconX, iconY - 4);
|
|
204
|
+
ctx.lineTo(iconX + iconSize / 2, iconY + 2);
|
|
205
|
+
ctx.lineTo(iconX + iconSize, iconY - 4);
|
|
206
|
+
ctx.stroke();
|
|
207
|
+
} else {
|
|
208
|
+
// Chevron right
|
|
209
|
+
ctx.beginPath();
|
|
210
|
+
ctx.moveTo(iconX + 2, iconY - iconSize / 2);
|
|
211
|
+
ctx.lineTo(iconX + 8, iconY);
|
|
212
|
+
ctx.lineTo(iconX + 2, iconY + iconSize / 2);
|
|
213
|
+
ctx.stroke();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
currentX += iconSize + 8;
|
|
217
|
+
} else {
|
|
218
|
+
currentX += 24; // Espace pour aligner avec les nœuds parents
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Icône du nœud
|
|
222
|
+
if (this.showIcons && node.icon) {
|
|
223
|
+
const iconSize = 20;
|
|
224
|
+
const iconY = nodeY + this.nodeHeight / 2 - iconSize / 2;
|
|
225
|
+
|
|
226
|
+
// Dessiner un simple carré coloré comme icône (peut être personnalisé)
|
|
227
|
+
ctx.fillStyle = node.icon;
|
|
228
|
+
ctx.fillRect(currentX, iconY, iconSize, iconSize);
|
|
229
|
+
|
|
230
|
+
currentX += iconSize + 8;
|
|
231
|
+
} else if (this.showIcons) {
|
|
232
|
+
// Icône par défaut (dossier ou fichier)
|
|
233
|
+
const iconSize = 20;
|
|
234
|
+
const iconY = nodeY + this.nodeHeight / 2 - iconSize / 2;
|
|
235
|
+
|
|
236
|
+
ctx.strokeStyle = this.iconColor;
|
|
237
|
+
ctx.lineWidth = 2;
|
|
238
|
+
|
|
239
|
+
if (hasChildren) {
|
|
240
|
+
// Icône dossier
|
|
241
|
+
ctx.beginPath();
|
|
242
|
+
ctx.moveTo(currentX, iconY + 4);
|
|
243
|
+
ctx.lineTo(currentX, iconY + iconSize);
|
|
244
|
+
ctx.lineTo(currentX + iconSize, iconY + iconSize);
|
|
245
|
+
ctx.lineTo(currentX + iconSize, iconY + 4);
|
|
246
|
+
ctx.lineTo(currentX + iconSize * 0.6, iconY + 4);
|
|
247
|
+
ctx.lineTo(currentX + iconSize * 0.5, iconY);
|
|
248
|
+
ctx.lineTo(currentX, iconY);
|
|
249
|
+
ctx.closePath();
|
|
250
|
+
ctx.stroke();
|
|
251
|
+
} else {
|
|
252
|
+
// Icône fichier
|
|
253
|
+
ctx.beginPath();
|
|
254
|
+
ctx.moveTo(currentX, iconY);
|
|
255
|
+
ctx.lineTo(currentX + iconSize * 0.7, iconY);
|
|
256
|
+
ctx.lineTo(currentX + iconSize, iconY + iconSize * 0.3);
|
|
257
|
+
ctx.lineTo(currentX + iconSize, iconY + iconSize);
|
|
258
|
+
ctx.lineTo(currentX, iconY + iconSize);
|
|
259
|
+
ctx.closePath();
|
|
260
|
+
ctx.stroke();
|
|
261
|
+
|
|
262
|
+
// Coin plié
|
|
263
|
+
ctx.beginPath();
|
|
264
|
+
ctx.moveTo(currentX + iconSize * 0.7, iconY);
|
|
265
|
+
ctx.lineTo(currentX + iconSize * 0.7, iconY + iconSize * 0.3);
|
|
266
|
+
ctx.lineTo(currentX + iconSize, iconY + iconSize * 0.3);
|
|
267
|
+
ctx.stroke();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
currentX += iconSize + 8;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Label
|
|
274
|
+
ctx.fillStyle = this.textColor;
|
|
275
|
+
ctx.font = '14px -apple-system, BlinkMacSystemFont, Roboto, sans-serif';
|
|
276
|
+
ctx.textAlign = 'left';
|
|
277
|
+
ctx.textBaseline = 'middle';
|
|
278
|
+
|
|
279
|
+
const maxWidth = this.width - (currentX - this.x) - 16;
|
|
280
|
+
let displayText = node.label;
|
|
281
|
+
|
|
282
|
+
// Tronquer si nécessaire
|
|
283
|
+
if (ctx.measureText(displayText).width > maxWidth) {
|
|
284
|
+
while (ctx.measureText(displayText + '...').width > maxWidth && displayText.length > 0) {
|
|
285
|
+
displayText = displayText.slice(0, -1);
|
|
286
|
+
}
|
|
287
|
+
displayText += '...';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
ctx.fillText(displayText, currentX, nodeY + this.nodeHeight / 2);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Trouve le nœud à une position
|
|
295
|
+
* @param {number} x - Coordonnée X
|
|
296
|
+
* @param {number} y - Coordonnée Y
|
|
297
|
+
* @returns {Object|null} Nœud trouvé
|
|
298
|
+
* @private
|
|
299
|
+
*/
|
|
300
|
+
getNodeAtPosition(x, y) {
|
|
301
|
+
const relY = y - this.y;
|
|
302
|
+
const index = Math.floor(relY / this.nodeHeight);
|
|
303
|
+
const flattenedNodes = this.getFlattenedNodes();
|
|
304
|
+
|
|
305
|
+
if (index >= 0 && index < flattenedNodes.length) {
|
|
306
|
+
return flattenedNodes[index];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Vérifie si le clic est sur l'icône expand
|
|
314
|
+
* @param {number} x - Coordonnée X
|
|
315
|
+
* @param {Object} node - Nœud
|
|
316
|
+
* @returns {boolean} True si clic sur expand
|
|
317
|
+
* @private
|
|
318
|
+
*/
|
|
319
|
+
isClickOnExpand(x, node) {
|
|
320
|
+
const indent = node.level * this.indentSize;
|
|
321
|
+
const expandX = this.x + 16 + indent;
|
|
322
|
+
return x >= expandX && x <= expandX + 16;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Vérifie si un point est dans les limites
|
|
327
|
+
* @param {number} x - Coordonnée X
|
|
328
|
+
* @param {number} y - Coordonnée Y
|
|
329
|
+
* @returns {boolean} True si le point est dans le composant
|
|
330
|
+
*/
|
|
331
|
+
isPointInside(x, y) {
|
|
332
|
+
return x >= this.x &&
|
|
333
|
+
x <= this.x + this.width &&
|
|
334
|
+
y >= this.y &&
|
|
335
|
+
y <= this.y + this.height;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Gère le clic
|
|
340
|
+
*/
|
|
341
|
+
onClick() {
|
|
342
|
+
// Géré dans onPress pour avoir les coordonnées
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Gère la pression
|
|
347
|
+
* @param {number} x - Coordonnée X
|
|
348
|
+
* @param {number} y - Coordonnée Y
|
|
349
|
+
*/
|
|
350
|
+
onPress(x, y) {
|
|
351
|
+
const node = this.getNodeAtPosition(x, y);
|
|
352
|
+
|
|
353
|
+
if (node) {
|
|
354
|
+
const hasChildren = node.children && node.children.length > 0;
|
|
355
|
+
|
|
356
|
+
if (hasChildren && this.isClickOnExpand(x, node)) {
|
|
357
|
+
// Clic sur l'icône expand/collapse
|
|
358
|
+
this.toggleNode(node);
|
|
359
|
+
} else {
|
|
360
|
+
// Clic sur le nœud lui-même
|
|
361
|
+
this.selectNode(node);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Gère le mouvement
|
|
368
|
+
* @param {number} x - Coordonnée X
|
|
369
|
+
* @param {number} y - Coordonnée Y
|
|
370
|
+
*/
|
|
371
|
+
onMove(x, y) {
|
|
372
|
+
this.hoveredNode = this.getNodeAtPosition(x, y);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Développe tous les nœuds
|
|
377
|
+
*/
|
|
378
|
+
expandAll() {
|
|
379
|
+
const expandRecursive = (nodes) => {
|
|
380
|
+
for (let node of nodes) {
|
|
381
|
+
if (node.children && node.children.length > 0) {
|
|
382
|
+
this.expandedNodes.add(node.id);
|
|
383
|
+
expandRecursive(node.children);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
expandRecursive(this.nodes);
|
|
389
|
+
this.updateHeight();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Replie tous les nœuds
|
|
394
|
+
*/
|
|
395
|
+
collapseAll() {
|
|
396
|
+
this.expandedNodes.clear();
|
|
397
|
+
this.updateHeight();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Trouve un nœud par son ID
|
|
402
|
+
* @param {string} id - ID du nœud
|
|
403
|
+
* @param {Array} [nodes=this.nodes] - Nœuds à chercher
|
|
404
|
+
* @returns {Object|null} Nœud trouvé
|
|
405
|
+
*/
|
|
406
|
+
findNodeById(id, nodes = this.nodes) {
|
|
407
|
+
for (let node of nodes) {
|
|
408
|
+
if (node.id === id) return node;
|
|
409
|
+
|
|
410
|
+
if (node.children) {
|
|
411
|
+
const found = this.findNodeById(id, node.children);
|
|
412
|
+
if (found) return found;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export default TreeView;
|