@umbraci/jsmind 0.10.15 → 0.10.17
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/dist/jsmind.history.js +1 -1
- package/dist/jsmind.history.js.map +1 -1
- package/es/jsmind.history.js +1 -1
- package/es/jsmind.history.js.map +1 -1
- package/lib/jsmind.history.js +1 -1
- package/lib/jsmind.history.js.map +1 -1
- package/package.json +1 -1
- package/types/generated/jsmind.d.ts +0 -194
- package/types/generated/jsmind.mind.d.ts +0 -8
- package/types/generated/jsmind.option.d.ts +0 -5
- package/types/generated/jsmind.view_provider.d.ts +0 -27
- package/types/generated/plugins/history/history-diff.d.ts +24 -37
- package/types/generated/plugins/jsmind.multi-select.d.ts +238 -0
|
@@ -78,10 +78,6 @@ declare class jsMind {
|
|
|
78
78
|
version: string;
|
|
79
79
|
initialized: boolean;
|
|
80
80
|
mind: Mind;
|
|
81
|
-
/** @type {'single'|'multi'|null} */
|
|
82
|
-
_selection_mode: "single" | "multi" | null;
|
|
83
|
-
/** @type {import('./jsmind.node.js').Node|null} */
|
|
84
|
-
_last_selected_node: import("./jsmind.node.js").Node | null;
|
|
85
81
|
/** @type {Array<(type: number, data: EventData) => void>} */
|
|
86
82
|
event_handles: Array<(type: number, data: EventData) => void>;
|
|
87
83
|
/** Initialize sub-systems and plugins. */
|
|
@@ -336,24 +332,8 @@ declare class jsMind {
|
|
|
336
332
|
* @returns {import('./jsmind.node.js').Node|null} Node instance or null
|
|
337
333
|
*/
|
|
338
334
|
get_selected_node(): import("./jsmind.node.js").Node | null;
|
|
339
|
-
/**
|
|
340
|
-
* Get all currently selected nodes.
|
|
341
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
342
|
-
*/
|
|
343
|
-
get_selected_nodes(): import("./jsmind.node.js").Node[];
|
|
344
335
|
/** clear selection */
|
|
345
336
|
select_clear(): void;
|
|
346
|
-
/**
|
|
347
|
-
* Toggle multi-selection for a node (and optionally descendants).
|
|
348
|
-
* @param {string | import('./jsmind.node.js').Node} node
|
|
349
|
-
*/
|
|
350
|
-
toggle_subtree_selection(node: string | import("./jsmind.node.js").Node): void;
|
|
351
|
-
/**
|
|
352
|
-
* Determine whether a node is currently selected.
|
|
353
|
-
* @param {string | import('./jsmind.node.js').Node} node
|
|
354
|
-
* @returns {boolean}
|
|
355
|
-
*/
|
|
356
|
-
is_node_selected(node: string | import("./jsmind.node.js").Node): boolean;
|
|
357
337
|
/** @param {string | import('./jsmind.node.js').Node} node */
|
|
358
338
|
is_node_visible(node: string | import("./jsmind.node.js").Node): boolean;
|
|
359
339
|
/**
|
|
@@ -361,180 +341,6 @@ declare class jsMind {
|
|
|
361
341
|
* @param {string | import('./jsmind.node.js').Node} node
|
|
362
342
|
*/
|
|
363
343
|
scroll_node_to_center(node: string | import("./jsmind.node.js").Node): void;
|
|
364
|
-
/**
|
|
365
|
-
* Add nodes into the current selection set without clearing existing ones.
|
|
366
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
367
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
368
|
-
* @private
|
|
369
|
-
*/
|
|
370
|
-
/**
|
|
371
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
372
|
-
* @param {{focusNode?: import('./jsmind.node.js').Node}=} options
|
|
373
|
-
* @private
|
|
374
|
-
*/
|
|
375
|
-
private _append_selection;
|
|
376
|
-
/**
|
|
377
|
-
* Remove nodes from the current selection set.
|
|
378
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
379
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
380
|
-
* @private
|
|
381
|
-
*/
|
|
382
|
-
private _remove_selection;
|
|
383
|
-
/**
|
|
384
|
-
* Deselect a node and all its descendants from the current selection.
|
|
385
|
-
* @param {string | import('./jsmind.node.js').Node} node
|
|
386
|
-
* @private
|
|
387
|
-
*/
|
|
388
|
-
private _deselect_subtree;
|
|
389
|
-
/**
|
|
390
|
-
* Clear all current selections and return the nodes that were cleared.
|
|
391
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
392
|
-
* @private
|
|
393
|
-
*/
|
|
394
|
-
private _clear_selection_state;
|
|
395
|
-
/**
|
|
396
|
-
* Collect a node and optionally its descendants respecting filters.
|
|
397
|
-
* @param {import('./jsmind.node.js').Node} node
|
|
398
|
-
* @param {{includeChildren?:boolean, respectFilter?:boolean, skipRootFilter?:boolean}=} config
|
|
399
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
400
|
-
* @private
|
|
401
|
-
*/
|
|
402
|
-
private _collect_subtree_nodes;
|
|
403
|
-
/**
|
|
404
|
-
* Ensure ancestors of provided nodes are also selected (up to first selected ancestor).
|
|
405
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
406
|
-
* @param {import('./jsmind.node.js').Node=} focusNode
|
|
407
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
408
|
-
* @private
|
|
409
|
-
*/
|
|
410
|
-
/**
|
|
411
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
412
|
-
* @param {import('./jsmind.node.js').Node=} focusNode
|
|
413
|
-
* @param {{requireAncestorChainSelected?: boolean}=} options
|
|
414
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
415
|
-
* @private
|
|
416
|
-
*/
|
|
417
|
-
private _ensure_ancestor_selection;
|
|
418
|
-
/**
|
|
419
|
-
* Get the configured selection filter callback, if any.
|
|
420
|
-
* @returns {((node: import('./jsmind.node.js').Node)=>boolean)|null}
|
|
421
|
-
* @private
|
|
422
|
-
*/
|
|
423
|
-
private _get_selection_filter;
|
|
424
|
-
/**
|
|
425
|
-
* Determine the multi-select mode based on event modifiers.
|
|
426
|
-
* Returns: null (single select), 'ctrl' (add/remove), 'shift' (range select)
|
|
427
|
-
* @param {MouseEvent} e
|
|
428
|
-
* @returns {null|'ctrl'|'shift'}
|
|
429
|
-
* @private
|
|
430
|
-
*/
|
|
431
|
-
private _get_multi_select_mode;
|
|
432
|
-
/**
|
|
433
|
-
* Toggle selection of a single node (add if not selected, remove if selected).
|
|
434
|
-
* Used for Ctrl+Click behavior.
|
|
435
|
-
* @param {string | import('./jsmind.node.js').Node} node_id
|
|
436
|
-
* @private
|
|
437
|
-
*/
|
|
438
|
-
private _toggle_node_selection;
|
|
439
|
-
/**
|
|
440
|
-
* Range select nodes for Shift+Click behavior.
|
|
441
|
-
* Logic:
|
|
442
|
-
* - If no nodes are currently selected: select all nodes under the clicked node
|
|
443
|
-
* - If nodes are already selected: select nodes in the range from first selected to clicked node
|
|
444
|
-
* @param {string | import('./jsmind.node.js').Node} node_id
|
|
445
|
-
* @private
|
|
446
|
-
*/
|
|
447
|
-
private _range_select_nodes;
|
|
448
|
-
/**
|
|
449
|
-
* Find all nodes between two nodes (for range selection).
|
|
450
|
-
* This includes both nodes and all nodes in between them in tree order.
|
|
451
|
-
* @param {import('./jsmind.node.js').Node} node1
|
|
452
|
-
* @param {import('./jsmind.node.js').Node} node2
|
|
453
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
454
|
-
* @private
|
|
455
|
-
*/
|
|
456
|
-
private _find_nodes_between;
|
|
457
|
-
/**
|
|
458
|
-
* Check whether ancestor is an ancestor of node.
|
|
459
|
-
* @param {import('./jsmind.node.js').Node} ancestor
|
|
460
|
-
* @param {import('./jsmind.node.js').Node} node
|
|
461
|
-
* @returns {boolean}
|
|
462
|
-
* @private
|
|
463
|
-
*/
|
|
464
|
-
private _is_ancestor_of;
|
|
465
|
-
/**
|
|
466
|
-
* Return nodes along the ancestor->descendant chain, inclusive. If 'ancestor' is not actually
|
|
467
|
-
* an ancestor of 'descendant', returns empty array.
|
|
468
|
-
* @param {import('./jsmind.node.js').Node} ancestor
|
|
469
|
-
* @param {import('./jsmind.node.js').Node} descendant
|
|
470
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
471
|
-
* @private
|
|
472
|
-
*/
|
|
473
|
-
private _get_path_nodes;
|
|
474
|
-
/**
|
|
475
|
-
* Find nearest selected ancestor of the given node from current selection set.
|
|
476
|
-
* @param {import('./jsmind.node.js').Node} node
|
|
477
|
-
* @returns {import('./jsmind.node.js').Node|null}
|
|
478
|
-
* @private
|
|
479
|
-
*/
|
|
480
|
-
private _find_nearest_selected_ancestor;
|
|
481
|
-
/**
|
|
482
|
-
* Find lowest common ancestor of two nodes.
|
|
483
|
-
* @param {import('./jsmind.node.js').Node} a
|
|
484
|
-
* @param {import('./jsmind.node.js').Node} b
|
|
485
|
-
* @returns {import('./jsmind.node.js').Node|null}
|
|
486
|
-
* @private
|
|
487
|
-
*/
|
|
488
|
-
private _find_lca;
|
|
489
|
-
/**
|
|
490
|
-
* Given a lowest common ancestor 'lca' and a descendant 'node',
|
|
491
|
-
* return the direct child of lca that lies on the path to node.
|
|
492
|
-
* Returns null if node is not a descendant of lca or node === lca.
|
|
493
|
-
* @param {import('./jsmind.node.js').Node} lca
|
|
494
|
-
* @param {import('./jsmind.node.js').Node} node
|
|
495
|
-
* @returns {import('./jsmind.node.js').Node|null}
|
|
496
|
-
* @private
|
|
497
|
-
*/
|
|
498
|
-
private _child_on_path;
|
|
499
|
-
/**
|
|
500
|
-
* From a list of nodes, remove those that are ancestors of any other node in the same list.
|
|
501
|
-
* Keeps only the deepest nodes so that we don't auto-select parents implicitly.
|
|
502
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
503
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
504
|
-
* @private
|
|
505
|
-
*/
|
|
506
|
-
private _remove_ancestor_nodes;
|
|
507
|
-
/**
|
|
508
|
-
* From a list of nodes, remove those that are descendants of any other node in the same list.
|
|
509
|
-
* Keeps only top-most nodes so that expanding subtrees covers full branches across siblings.
|
|
510
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
511
|
-
* @returns {import('./jsmind.node.js').Node[]}
|
|
512
|
-
* @private
|
|
513
|
-
*/
|
|
514
|
-
private _remove_descendant_nodes;
|
|
515
|
-
/**
|
|
516
|
-
* Expand a set of base nodes with all their descendants (and themselves).
|
|
517
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
518
|
-
* @param {{respectFilter?: boolean}=} opts
|
|
519
|
-
* @returns {Set<import('./jsmind.node.js').Node>}
|
|
520
|
-
* @private
|
|
521
|
-
*/
|
|
522
|
-
private _expand_with_descendants;
|
|
523
|
-
/**
|
|
524
|
-
* Promote parents into selection ONLY when all their direct children are selected
|
|
525
|
-
* AND at least one ancestor of that parent is already selected (in previous selection set).
|
|
526
|
-
* This avoids auto-selecting parents when only siblings are selected.
|
|
527
|
-
* @param {Set<import('./jsmind.node.js').Node>} set
|
|
528
|
-
* @returns {Set<import('./jsmind.node.js').Node>}
|
|
529
|
-
* @private
|
|
530
|
-
*/
|
|
531
|
-
private _promote_parents_when_children_selected;
|
|
532
|
-
/**
|
|
533
|
-
* Determine selection mode based on current selection size.
|
|
534
|
-
* @returns {'single'|'multi'|null}
|
|
535
|
-
* @private
|
|
536
|
-
*/
|
|
537
|
-
private _derive_selection_mode;
|
|
538
344
|
/**
|
|
539
345
|
* Find the previous sibling node of the given node.
|
|
540
346
|
*
|
|
@@ -9,8 +9,6 @@ export class Mind {
|
|
|
9
9
|
root: Node | null;
|
|
10
10
|
/** @type {Node | null} */
|
|
11
11
|
selected: Node | null;
|
|
12
|
-
/** @type {Set<Node>} */
|
|
13
|
-
selected_nodes: Set<Node>;
|
|
14
12
|
/** @type {Record<string, Node>} */
|
|
15
13
|
nodes: Record<string, Node>;
|
|
16
14
|
/**
|
|
@@ -108,12 +106,6 @@ export class Mind {
|
|
|
108
106
|
* @returns {boolean}
|
|
109
107
|
*/
|
|
110
108
|
remove_node(node: Node): boolean;
|
|
111
|
-
/**
|
|
112
|
-
* Remove a node and its subtree from the cached selection set.
|
|
113
|
-
* @param {Node} node
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
private _purge_selection;
|
|
117
109
|
/**
|
|
118
110
|
* Put node into the map if id is not taken.
|
|
119
111
|
* @param {Node} node
|
|
@@ -60,11 +60,6 @@ export type JsMindRuntimeOptions = {
|
|
|
60
60
|
mapping?: Record<string, number | number[]>;
|
|
61
61
|
id_generator?: () => string;
|
|
62
62
|
};
|
|
63
|
-
selection?: {
|
|
64
|
-
enable_multi_select?: boolean;
|
|
65
|
-
include_descendants?: boolean;
|
|
66
|
-
filter?: (node: import("./jsmind.node.js").Node) => boolean;
|
|
67
|
-
};
|
|
68
63
|
fieldNames?: {
|
|
69
64
|
id?: string;
|
|
70
65
|
topic?: string;
|
|
@@ -71,8 +71,6 @@ export class ViewProvider {
|
|
|
71
71
|
h: number;
|
|
72
72
|
};
|
|
73
73
|
selected_node: import("./jsmind.node.js").Node;
|
|
74
|
-
/** @type {Map<string, import('./jsmind.node.js').Node>} */
|
|
75
|
-
multi_selected_nodes: Map<string, import("./jsmind.node.js").Node>;
|
|
76
74
|
editing_node: import("./jsmind.node.js").Node;
|
|
77
75
|
graph: {
|
|
78
76
|
view: ViewProvider;
|
|
@@ -255,19 +253,6 @@ export class ViewProvider {
|
|
|
255
253
|
select_node(node: import("./jsmind.node.js").Node | null): void;
|
|
256
254
|
/** Clear node selection. */
|
|
257
255
|
select_clear(): void;
|
|
258
|
-
/**
|
|
259
|
-
* Append nodes to the current selection without clearing existing ones.
|
|
260
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
261
|
-
* @param {import('./jsmind.node.js').Node=} focus_node
|
|
262
|
-
*/
|
|
263
|
-
append_selected_nodes(nodes: import("./jsmind.node.js").Node[], focus_node?: import("./jsmind.node.js").Node | undefined): void;
|
|
264
|
-
/**
|
|
265
|
-
* Remove the provided nodes from selection state.
|
|
266
|
-
* @param {import('./jsmind.node.js').Node[]} nodes
|
|
267
|
-
*/
|
|
268
|
-
remove_selected_nodes(nodes: import("./jsmind.node.js").Node[]): void;
|
|
269
|
-
/** Clear all selections at once. */
|
|
270
|
-
clear_all_selected_nodes(): void;
|
|
271
256
|
/**
|
|
272
257
|
* Get currently editing node.
|
|
273
258
|
* @returns {import('./jsmind.node.js').Node|null} Currently editing node
|
|
@@ -344,18 +329,6 @@ export class ViewProvider {
|
|
|
344
329
|
restore_selected_node_custom_style(node: import("./jsmind.node.js").Node): void;
|
|
345
330
|
/** @param {import('./jsmind.node.js').Node} node */
|
|
346
331
|
clear_selected_node_custom_style(node: import("./jsmind.node.js").Node): void;
|
|
347
|
-
/**
|
|
348
|
-
* Mark the DOM/state for a selected node.
|
|
349
|
-
* @param {import('./jsmind.node.js').Node} node
|
|
350
|
-
* @private
|
|
351
|
-
*/
|
|
352
|
-
private _mark_node_selected;
|
|
353
|
-
/**
|
|
354
|
-
* Remove DOM/state selection for a node.
|
|
355
|
-
* @param {import('./jsmind.node.js').Node} node
|
|
356
|
-
* @private
|
|
357
|
-
*/
|
|
358
|
-
private _unmark_node_selected;
|
|
359
332
|
clear_lines(): void;
|
|
360
333
|
show_lines(): void;
|
|
361
334
|
/**
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
export function flatten(tree: NodeTreeFormat | NodeTreeData, opts?: FlattenOptions): Map<string, FlatNode>;
|
|
24
24
|
/**
|
|
25
25
|
* Compute diff between two snapshots.
|
|
26
|
+
* Always categorizes updates into moved/modified/movedAndModified using LIS algorithm for precise move detection.
|
|
26
27
|
*
|
|
27
28
|
* Note: When using custom fieldNames, make sure to pass the correct field names in opts.fields.
|
|
28
29
|
* For example, if you configured fieldNames: { topic: 'name' }, you should pass fields: ['name', 'data', 'id'].
|
|
@@ -31,22 +32,26 @@ export function flatten(tree: NodeTreeFormat | NodeTreeData, opts?: FlattenOptio
|
|
|
31
32
|
* @param {NodeTreeFormat|NodeTreeData} a - First snapshot (before)
|
|
32
33
|
* @param {NodeTreeFormat|NodeTreeData} b - Second snapshot (after)
|
|
33
34
|
* @param {DiffOptions} [opts] - Diff options
|
|
34
|
-
* @returns {DiffResult} Diff result with created,
|
|
35
|
+
* @returns {DiffResult} Diff result with created, deleted, moved, modified, and movedAndModified nodes
|
|
35
36
|
*
|
|
36
37
|
* @example
|
|
37
38
|
* // Basic usage with default fieldNames
|
|
38
39
|
* const result = diff(snapshot1, snapshot2);
|
|
39
40
|
* console.log(result.created); // Newly created nodes
|
|
40
|
-
* console.log(result.updated); // Updated nodes with changes
|
|
41
41
|
* console.log(result.deleted); // Deleted nodes
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* // With categorization
|
|
45
|
-
* const result = diff(snapshot1, snapshot2, { categorize: true });
|
|
46
|
-
* console.log(result.moved); // Nodes that were only moved
|
|
42
|
+
* console.log(result.moved); // Nodes that were only moved (cross-parent or reordered)
|
|
47
43
|
* console.log(result.modified); // Nodes that were only modified
|
|
48
44
|
* console.log(result.movedAndModified); // Nodes that were both moved and modified
|
|
49
45
|
*
|
|
46
|
+
* // Check move type
|
|
47
|
+
* result.moved.forEach(node => {
|
|
48
|
+
* if (node.moveInfo.moveType === 'cross-parent') {
|
|
49
|
+
* console.log(`${node.id} moved from ${node.moveInfo.fromParent} to ${node.moveInfo.toParent}`);
|
|
50
|
+
* } else if (node.moveInfo.moveType === 'reorder') {
|
|
51
|
+
* console.log(`${node.id} reordered from index ${node.moveInfo.fromOrder} to ${node.moveInfo.toOrder}`);
|
|
52
|
+
* }
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
50
55
|
* @example
|
|
51
56
|
* // With custom fieldNames: { topic: 'name' }
|
|
52
57
|
* const result = diff(snapshot1, snapshot2, { fields: ['name', 'data', 'id'] });
|
|
@@ -58,12 +63,7 @@ export function flatten(tree: NodeTreeFormat | NodeTreeData, opts?: FlattenOptio
|
|
|
58
63
|
* // ... make changes ...
|
|
59
64
|
* const after = jm.get_data('node_tree');
|
|
60
65
|
* const result = jm.history.diff(before, after);
|
|
61
|
-
* // fieldNames are automatically applied,
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* // Ignore index changes caused by preceding node deletions
|
|
65
|
-
* const result = jm.history.diff(before, after, { ignoreDeletionShift: true });
|
|
66
|
-
* // Now nodes that only change index due to deletion of previous siblings won't be marked as moved
|
|
66
|
+
* // fieldNames are automatically applied, LIS algorithm is used for precise move detection
|
|
67
67
|
*/
|
|
68
68
|
export function diff(a: NodeTreeFormat | NodeTreeData, b: NodeTreeFormat | NodeTreeData, opts?: DiffOptions): DiffResult;
|
|
69
69
|
export type NodeTreeFormat = {
|
|
@@ -135,6 +135,10 @@ export type UpdatedNode = {
|
|
|
135
135
|
changes: ChangeDetail[];
|
|
136
136
|
};
|
|
137
137
|
export type MoveInfo = {
|
|
138
|
+
/**
|
|
139
|
+
* - Type of move: 'cross-parent' for different parent, 'reorder' for same parent
|
|
140
|
+
*/
|
|
141
|
+
moveType: "cross-parent" | "reorder";
|
|
138
142
|
/**
|
|
139
143
|
* - Whether parent changed
|
|
140
144
|
*/
|
|
@@ -223,10 +227,6 @@ export type DiffResult = {
|
|
|
223
227
|
* - Newly created nodes
|
|
224
228
|
*/
|
|
225
229
|
created: FlatNode[];
|
|
226
|
-
/**
|
|
227
|
-
* - Updated nodes (all changes)
|
|
228
|
-
*/
|
|
229
|
-
updated: UpdatedNode[];
|
|
230
230
|
/**
|
|
231
231
|
* - Deleted nodes
|
|
232
232
|
*/
|
|
@@ -236,17 +236,17 @@ export type DiffResult = {
|
|
|
236
236
|
*/
|
|
237
237
|
truncated: boolean;
|
|
238
238
|
/**
|
|
239
|
-
* - Nodes that were only moved
|
|
239
|
+
* - Nodes that were only moved
|
|
240
240
|
*/
|
|
241
|
-
moved
|
|
241
|
+
moved: MovedNode[];
|
|
242
242
|
/**
|
|
243
|
-
* - Nodes that were only modified
|
|
243
|
+
* - Nodes that were only modified
|
|
244
244
|
*/
|
|
245
|
-
modified
|
|
245
|
+
modified: ModifiedNode[];
|
|
246
246
|
/**
|
|
247
|
-
* - Nodes that were both moved and modified
|
|
247
|
+
* - Nodes that were both moved and modified
|
|
248
248
|
*/
|
|
249
|
-
movedAndModified
|
|
249
|
+
movedAndModified: MovedAndModifiedNode[];
|
|
250
250
|
};
|
|
251
251
|
export type FlattenOptions = {
|
|
252
252
|
/**
|
|
@@ -273,21 +273,16 @@ export type FlattenOptions = {
|
|
|
273
273
|
export type DiffOptions = {
|
|
274
274
|
/**
|
|
275
275
|
* - Array of field names to compare. Defaults to ['topic', 'data', 'id'].
|
|
276
|
-
* When using
|
|
277
|
-
* ['name', 'data', 'key'] to match the actual field names in the data.
|
|
278
|
-
* Note: When using jm.history.diff(), this is automatically handled based
|
|
279
|
-
* on the configured fieldNames, so you don't need to specify it manually.
|
|
276
|
+
* Note: When using jm.history.diff(), this is automatically handled.
|
|
280
277
|
*/
|
|
281
278
|
fields?: string[];
|
|
282
279
|
/**
|
|
283
280
|
* - The field name to use as the node ID. Defaults to 'id'.
|
|
284
|
-
* When using custom fieldNames (e.g., { id: 'key' }), this should be 'key'.
|
|
285
281
|
* Note: When using jm.history.diff(), this is automatically handled.
|
|
286
282
|
*/
|
|
287
283
|
idKey?: string;
|
|
288
284
|
/**
|
|
289
285
|
* - The field name to use for children array. Defaults to 'children'.
|
|
290
|
-
* When using custom fieldNames (e.g., { children: 'items' }), this should be 'items'.
|
|
291
286
|
* Note: When using jm.history.diff(), this is automatically handled.
|
|
292
287
|
*/
|
|
293
288
|
childrenKey?: string;
|
|
@@ -299,12 +294,4 @@ export type DiffOptions = {
|
|
|
299
294
|
* - Maximum number of diff results. Defaults to 5000
|
|
300
295
|
*/
|
|
301
296
|
maxSize?: number;
|
|
302
|
-
/**
|
|
303
|
-
* - Whether to categorize updates into moved/modified/movedAndModified. Defaults to false
|
|
304
|
-
*/
|
|
305
|
-
categorize?: boolean;
|
|
306
|
-
/**
|
|
307
|
-
* - Whether to ignore index changes caused by preceding node deletions. When true, nodes that only change index due to deletion of previous siblings won't be marked as moved. Defaults to false
|
|
308
|
-
*/
|
|
309
|
-
ignoreDeletionShift?: boolean;
|
|
310
297
|
};
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Select Plugin - Enhanced plugin for jsMind
|
|
3
|
+
*/
|
|
4
|
+
export class MultiSelectPlugin extends EnhancedPlugin {
|
|
5
|
+
/**
|
|
6
|
+
* @param {{ jm: import('../jsmind.js').default, pluginOpt: object }} params
|
|
7
|
+
*/
|
|
8
|
+
constructor({ jm, pluginOpt }: {
|
|
9
|
+
jm: import("../jsmind.js").default;
|
|
10
|
+
pluginOpt: object;
|
|
11
|
+
});
|
|
12
|
+
options: any;
|
|
13
|
+
_mounted: boolean;
|
|
14
|
+
_core: MultiSelectCore;
|
|
15
|
+
_listener: (type: any, data: any) => void;
|
|
16
|
+
_enabled: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Initialize core and mount API
|
|
19
|
+
*/
|
|
20
|
+
_initCore(): void;
|
|
21
|
+
_original_select_node: any;
|
|
22
|
+
_original_select_clear: any;
|
|
23
|
+
_domClickHandler: (e: any) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Mount API to jsMind instance
|
|
26
|
+
*/
|
|
27
|
+
_mountAPI(): void;
|
|
28
|
+
setEnabled(flag: any): void;
|
|
29
|
+
setOptions(partial: any): void;
|
|
30
|
+
}
|
|
31
|
+
export default MultiSelectPlugin;
|
|
32
|
+
/**
|
|
33
|
+
* Default options for multi-select plugin.
|
|
34
|
+
*/
|
|
35
|
+
export type MultiSelectOptions = {
|
|
36
|
+
/**
|
|
37
|
+
* - Enable multi-select feature
|
|
38
|
+
*/
|
|
39
|
+
enable_multi_select?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* - Include descendants in subtree selection
|
|
42
|
+
*/
|
|
43
|
+
include_descendants?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* - Shift mode: false=simple subtree, true=advanced range
|
|
46
|
+
*/
|
|
47
|
+
shift_simple_mode?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* - Node filter function
|
|
50
|
+
*/
|
|
51
|
+
filter?: ((node: import("../jsmind.node.js").Node) => boolean) | null;
|
|
52
|
+
};
|
|
53
|
+
import { EnhancedPlugin } from '../jsmind.enhanced-plugin.js';
|
|
54
|
+
/**
|
|
55
|
+
* Multi-Select Core - Handles all multi-select logic
|
|
56
|
+
*/
|
|
57
|
+
export class MultiSelectCore {
|
|
58
|
+
/**
|
|
59
|
+
* @param {import('../jsmind.js').default} jm - jsMind instance
|
|
60
|
+
* @param {MultiSelectOptions} options - Plugin options
|
|
61
|
+
*/
|
|
62
|
+
constructor(jm: import("../jsmind.js").default, options: MultiSelectOptions);
|
|
63
|
+
jm: import("../jsmind.js").default;
|
|
64
|
+
options: MultiSelectOptions;
|
|
65
|
+
_selection_mode: string;
|
|
66
|
+
_last_selected_node: import("../jsmind.node.js").Node;
|
|
67
|
+
/**
|
|
68
|
+
* Ensure selection state is initialized
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private _ensure_selection_state;
|
|
72
|
+
/**
|
|
73
|
+
* Get all selected nodes
|
|
74
|
+
* @returns {string[]} Array of selected node IDs
|
|
75
|
+
*/
|
|
76
|
+
get_selected_nodes(): string[];
|
|
77
|
+
/**
|
|
78
|
+
* Check if a node is selected
|
|
79
|
+
* @param {string|import('../jsmind.node.js').Node} node - Node ID or Node instance
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
*/
|
|
82
|
+
is_node_selected(node: string | import("../jsmind.node.js").Node): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Select a single node (clears other selections)
|
|
85
|
+
* @param {string|import('../jsmind.node.js').Node} node - Node ID or Node instance
|
|
86
|
+
*/
|
|
87
|
+
select_node(node: string | import("../jsmind.node.js").Node): void;
|
|
88
|
+
/**
|
|
89
|
+
* Clear all selections
|
|
90
|
+
*/
|
|
91
|
+
select_clear(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Toggle node selection (equivalent to Ctrl/Cmd+Click)
|
|
94
|
+
* @param {string|import('../jsmind.node.js').Node} node - Node ID or Node instance
|
|
95
|
+
*/
|
|
96
|
+
toggle_node_selection(node: string | import("../jsmind.node.js").Node): void;
|
|
97
|
+
/**
|
|
98
|
+
* Toggle subtree selection
|
|
99
|
+
* @param {string|import('../jsmind.node.js').Node} node - Node ID or Node instance
|
|
100
|
+
*/
|
|
101
|
+
toggle_subtree_selection(node: string | import("../jsmind.node.js").Node, opts: any): void;
|
|
102
|
+
/**
|
|
103
|
+
* Get current selection mode
|
|
104
|
+
* @returns {'single'|'multi'|null}
|
|
105
|
+
*/
|
|
106
|
+
get_selection_mode(): "single" | "multi" | null;
|
|
107
|
+
/**
|
|
108
|
+
* Handle node click event
|
|
109
|
+
* @param {Object} payload - Click event payload
|
|
110
|
+
* @param {MouseEvent} payload.e - Mouse event
|
|
111
|
+
* @param {string} payload.node - Node ID
|
|
112
|
+
* @param {HTMLElement} payload.element - Node element
|
|
113
|
+
* @param {string} payload.evt - Event type
|
|
114
|
+
*/
|
|
115
|
+
_handle_node_click(payload: {
|
|
116
|
+
e: MouseEvent;
|
|
117
|
+
node: string;
|
|
118
|
+
element: HTMLElement;
|
|
119
|
+
evt: string;
|
|
120
|
+
}): void;
|
|
121
|
+
/**
|
|
122
|
+
* Handle node removed event
|
|
123
|
+
* @param {import('../jsmind.node.js').Node} node - Removed node
|
|
124
|
+
*/
|
|
125
|
+
_handle_node_removed(node: import("../jsmind.node.js").Node): void;
|
|
126
|
+
/**
|
|
127
|
+
* Get multi-select mode from event
|
|
128
|
+
* @param {MouseEvent} e - Mouse event
|
|
129
|
+
* @returns {'ctrl'|'shift'|null}
|
|
130
|
+
*/
|
|
131
|
+
_get_multi_select_mode(e: MouseEvent): "ctrl" | "shift" | null;
|
|
132
|
+
/**
|
|
133
|
+
* Append nodes to selection
|
|
134
|
+
* @param {import('../jsmind.node.js').Node[]} nodes - Nodes to select
|
|
135
|
+
* @param {Object} [options] - Options
|
|
136
|
+
* @param {import('../jsmind.node.js').Node} [options.focusNode] - Focus node
|
|
137
|
+
* @returns {import('../jsmind.node.js').Node[]} Actually added nodes
|
|
138
|
+
*/
|
|
139
|
+
_append_selection(nodes: import("../jsmind.node.js").Node[], options?: {
|
|
140
|
+
focusNode?: import("../jsmind.node.js").Node;
|
|
141
|
+
}): import("../jsmind.node.js").Node[];
|
|
142
|
+
/**
|
|
143
|
+
* Remove nodes from selection
|
|
144
|
+
* @param {import('../jsmind.node.js').Node[]} nodes - Nodes to deselect
|
|
145
|
+
* @returns {import('../jsmind.node.js').Node[]} Actually removed nodes
|
|
146
|
+
*/
|
|
147
|
+
_remove_selection(nodes: import("../jsmind.node.js").Node[]): import("../jsmind.node.js").Node[];
|
|
148
|
+
/**
|
|
149
|
+
* Deselect subtree
|
|
150
|
+
* @param {import('../jsmind.node.js').Node} node - Root node of subtree
|
|
151
|
+
*/
|
|
152
|
+
_deselect_subtree(node: import("../jsmind.node.js").Node): void;
|
|
153
|
+
/**
|
|
154
|
+
* Clear selection state
|
|
155
|
+
* @returns {import('../jsmind.node.js').Node[]} Removed nodes
|
|
156
|
+
*/
|
|
157
|
+
_clear_selection_state(): import("../jsmind.node.js").Node[];
|
|
158
|
+
/**
|
|
159
|
+
* Collect subtree nodes
|
|
160
|
+
* @param {import('../jsmind.node.js').Node} node - Root node
|
|
161
|
+
* @param {Object} options - Options
|
|
162
|
+
* @param {boolean} [options.includeChildren=true] - Include children
|
|
163
|
+
* @param {boolean} [options.respectFilter=false] - Respect filter
|
|
164
|
+
* @param {boolean} [options.skipRootFilter=false] - Skip root filter
|
|
165
|
+
* @returns {import('../jsmind.node.js').Node[]}
|
|
166
|
+
*/
|
|
167
|
+
_collect_subtree_nodes(node: import("../jsmind.node.js").Node, options: {
|
|
168
|
+
includeChildren?: boolean;
|
|
169
|
+
respectFilter?: boolean;
|
|
170
|
+
skipRootFilter?: boolean;
|
|
171
|
+
}): import("../jsmind.node.js").Node[];
|
|
172
|
+
/**
|
|
173
|
+
* Ensure ancestor selection
|
|
174
|
+
* @param {import('../jsmind.node.js').Node[]} nodes - Nodes
|
|
175
|
+
* @param {import('../jsmind.node.js').Node} focusNode - Focus node
|
|
176
|
+
* @param {Object} options - Options
|
|
177
|
+
* @returns {import('../jsmind.node.js').Node[]}
|
|
178
|
+
*/
|
|
179
|
+
_ensure_ancestor_selection(nodes: import("../jsmind.node.js").Node[], focusNode: import("../jsmind.node.js").Node, options: any): import("../jsmind.node.js").Node[];
|
|
180
|
+
/**
|
|
181
|
+
* Get selection filter
|
|
182
|
+
* @returns {Function|null}
|
|
183
|
+
*/
|
|
184
|
+
_get_selection_filter(): Function | null;
|
|
185
|
+
/**
|
|
186
|
+
* Range select nodes (advanced mode)
|
|
187
|
+
* @param {string} nodeId - Target node ID
|
|
188
|
+
*/
|
|
189
|
+
_range_select_nodes(nodeId: string): void;
|
|
190
|
+
/**
|
|
191
|
+
* Find nodes between two nodes
|
|
192
|
+
* @param {import('../jsmind.node.js').Node} from - Start node
|
|
193
|
+
* @param {import('../jsmind.node.js').Node} to - End node
|
|
194
|
+
* @returns {import('../jsmind.node.js').Node[]}
|
|
195
|
+
*/
|
|
196
|
+
_find_nodes_between(from: import("../jsmind.node.js").Node, to: import("../jsmind.node.js").Node): import("../jsmind.node.js").Node[];
|
|
197
|
+
/**
|
|
198
|
+
* Derive selection mode from current state
|
|
199
|
+
* @returns {'single'|'multi'|null}
|
|
200
|
+
*/
|
|
201
|
+
_derive_selection_mode(): "single" | "multi" | null;
|
|
202
|
+
/**
|
|
203
|
+
* Mark nodes as selected in view
|
|
204
|
+
* @param {import('../jsmind.node.js').Node[]} nodes - Nodes to mark
|
|
205
|
+
* @param {import('../jsmind.node.js').Node} focusNode - Focus node
|
|
206
|
+
*/
|
|
207
|
+
_mark_nodes_selected(nodes: import("../jsmind.node.js").Node[], focusNode: import("../jsmind.node.js").Node): void;
|
|
208
|
+
/**
|
|
209
|
+
* Mark a node as selected in view
|
|
210
|
+
* @param {import('../jsmind.node.js').Node} node - Node to mark
|
|
211
|
+
*/
|
|
212
|
+
_mark_node_selected(node: import("../jsmind.node.js").Node): void;
|
|
213
|
+
/**
|
|
214
|
+
* Unmark nodes as selected in view
|
|
215
|
+
* @param {import('../jsmind.node.js').Node[]} nodes - Nodes to unmark
|
|
216
|
+
*/
|
|
217
|
+
_unmark_nodes_selected(nodes: import("../jsmind.node.js").Node[]): void;
|
|
218
|
+
/**
|
|
219
|
+
* Unmark a node as selected in view
|
|
220
|
+
* @param {import('../jsmind.node.js').Node} node - Node to unmark
|
|
221
|
+
*/
|
|
222
|
+
_unmark_node_selected(node: import("../jsmind.node.js").Node): void;
|
|
223
|
+
/**
|
|
224
|
+
* Clear all selected nodes view
|
|
225
|
+
*/
|
|
226
|
+
_clear_all_selected_nodes_view(): void;
|
|
227
|
+
/**
|
|
228
|
+
* Invoke select event
|
|
229
|
+
* @param {Object} data - Event data
|
|
230
|
+
*/
|
|
231
|
+
_invoke_select_event(data: any): void;
|
|
232
|
+
/**
|
|
233
|
+
* Resolve node from ID or Node instance
|
|
234
|
+
* @param {string|import('../jsmind.node.js').Node} node - Node ID or Node instance
|
|
235
|
+
* @returns {import('../jsmind.node.js').Node|null}
|
|
236
|
+
*/
|
|
237
|
+
_resolve_node(node: string | import("../jsmind.node.js").Node): import("../jsmind.node.js").Node | null;
|
|
238
|
+
}
|