jqtree 1.8.7 → 1.8.9
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/bower.json +1 -1
- package/eslint.config.mjs +6 -1
- package/package.json +28 -27
- package/src/dataLoader.ts +38 -38
- package/src/dragAndDropHandler/binarySearch.ts +27 -0
- package/src/dragAndDropHandler/dragElement.ts +9 -9
- package/src/dragAndDropHandler/generateHitAreas.ts +21 -18
- package/src/dragAndDropHandler/index.ts +158 -179
- package/src/dragAndDropHandler/types.ts +1 -2
- package/src/elementsRenderer.ts +42 -42
- package/src/jqtreeOptions.ts +27 -27
- package/src/keyHandler.ts +47 -50
- package/src/mouseHandler.ts +152 -152
- package/src/node.ts +32 -34
- package/src/nodeElement/folderElement.ts +16 -19
- package/src/nodeElement/ghostDropHint.ts +8 -9
- package/src/nodeElement/index.ts +24 -31
- package/src/saveStateHandler.ts +72 -96
- package/src/scrollHandler/containerScrollParent.ts +58 -58
- package/src/scrollHandler/documentScrollParent.ts +60 -60
- package/src/scrollHandler.ts +17 -17
- package/src/selectNodeHandler.ts +7 -11
- package/src/tree.jquery.d.ts +37 -37
- package/src/tree.jquery.ts +939 -936
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +1393 -1407
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +2 -2
- package/tree.jquery.js.map +1 -1
- package/src/position.ts +0 -28
package/src/tree.jquery.ts
CHANGED
|
@@ -6,10 +6,9 @@ import { JQTreeOptions } from "./jqtreeOptions";
|
|
|
6
6
|
import KeyHandler from "./keyHandler";
|
|
7
7
|
import MouseHandler from "./mouseHandler";
|
|
8
8
|
import { PositionInfo } from "./mouseUtils";
|
|
9
|
-
import { Node } from "./node";
|
|
9
|
+
import { Node, Position } from "./node";
|
|
10
10
|
import NodeElement from "./nodeElement";
|
|
11
11
|
import FolderElement from "./nodeElement/folderElement";
|
|
12
|
-
import { getPosition } from "./position";
|
|
13
12
|
import SaveStateHandler, { SavedState } from "./saveStateHandler";
|
|
14
13
|
import ScrollHandler from "./scrollHandler";
|
|
15
14
|
import SelectNodeHandler from "./selectNodeHandler";
|
|
@@ -78,1211 +77,1215 @@ export class JqTreeWidget extends SimpleWidget<JQTreeOptions> {
|
|
|
78
77
|
private selectNodeHandler: SelectNodeHandler;
|
|
79
78
|
private tree: Node;
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
dataFilter,
|
|
87
|
-
dragAndDrop,
|
|
88
|
-
keyboardSupport,
|
|
89
|
-
onCanMove,
|
|
90
|
-
onCanMoveTo,
|
|
91
|
-
onCreateLi,
|
|
92
|
-
onDragMove,
|
|
93
|
-
onDragStop,
|
|
94
|
-
onGetStateFromStorage,
|
|
95
|
-
onIsMoveHandle,
|
|
96
|
-
onLoadFailed,
|
|
97
|
-
onLoading,
|
|
98
|
-
onSetStateFromStorage,
|
|
99
|
-
openedIcon,
|
|
100
|
-
openFolderDelay,
|
|
101
|
-
rtl,
|
|
102
|
-
saveState,
|
|
103
|
-
showEmptyFolder,
|
|
104
|
-
slide,
|
|
105
|
-
tabIndex,
|
|
106
|
-
} = this.options;
|
|
80
|
+
public addNodeAfter(
|
|
81
|
+
newNodeInfo: NodeData,
|
|
82
|
+
existingNode: Node,
|
|
83
|
+
): Node | null {
|
|
84
|
+
const newNode = existingNode.addAfter(newNodeInfo);
|
|
107
85
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const getNodeById = this.getNodeById.bind(this);
|
|
112
|
-
const getSelectedNode = this.getSelectedNode.bind(this);
|
|
113
|
-
const getTree = this.getTree.bind(this);
|
|
114
|
-
const isFocusOnTree = this.isFocusOnTree.bind(this);
|
|
115
|
-
const loadData = this.loadData.bind(this);
|
|
116
|
-
const openNode = this.openNodeInternal.bind(this);
|
|
117
|
-
const refreshElements = this.refreshElements.bind(this);
|
|
118
|
-
const refreshHitAreas = this.refreshHitAreas.bind(this);
|
|
119
|
-
const selectNode = this.selectNode.bind(this);
|
|
120
|
-
const $treeElement = this.element;
|
|
121
|
-
const treeElement = this.element.get(0) as HTMLElement;
|
|
122
|
-
const triggerEvent = this.triggerEvent.bind(this);
|
|
86
|
+
if (newNode) {
|
|
87
|
+
this.refreshElements(existingNode.parent);
|
|
88
|
+
}
|
|
123
89
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
});
|
|
90
|
+
return newNode;
|
|
91
|
+
}
|
|
127
92
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
selectNodeHandler.removeFromSelection.bind(selectNodeHandler);
|
|
136
|
-
const getMouseDelay = () => this.options.startDndDelay ?? 0;
|
|
93
|
+
public addNodeBefore(
|
|
94
|
+
newNodeInfo: NodeData,
|
|
95
|
+
existingNode?: Node,
|
|
96
|
+
): Node | null {
|
|
97
|
+
if (!existingNode) {
|
|
98
|
+
throw Error(PARAM_IS_EMPTY + "existingNode");
|
|
99
|
+
}
|
|
137
100
|
|
|
138
|
-
const
|
|
139
|
-
dataFilter,
|
|
140
|
-
loadData,
|
|
141
|
-
onLoadFailed,
|
|
142
|
-
onLoading,
|
|
143
|
-
treeElement,
|
|
144
|
-
triggerEvent,
|
|
145
|
-
});
|
|
101
|
+
const newNode = existingNode.addBefore(newNodeInfo);
|
|
146
102
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
getSelectedNodes,
|
|
151
|
-
getTree,
|
|
152
|
-
onGetStateFromStorage,
|
|
153
|
-
onSetStateFromStorage,
|
|
154
|
-
openNode,
|
|
155
|
-
refreshElements,
|
|
156
|
-
removeFromSelection,
|
|
157
|
-
saveState,
|
|
158
|
-
});
|
|
103
|
+
if (newNode) {
|
|
104
|
+
this.refreshElements(existingNode.parent);
|
|
105
|
+
}
|
|
159
106
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
treeElement,
|
|
163
|
-
});
|
|
107
|
+
return newNode;
|
|
108
|
+
}
|
|
164
109
|
|
|
165
|
-
|
|
110
|
+
public addParentNode(
|
|
111
|
+
newNodeInfo: NodeData,
|
|
112
|
+
existingNode?: Node,
|
|
113
|
+
): Node | null {
|
|
114
|
+
if (!existingNode) {
|
|
115
|
+
throw Error(PARAM_IS_EMPTY + "existingNode");
|
|
116
|
+
}
|
|
166
117
|
|
|
167
|
-
const
|
|
168
|
-
autoEscape,
|
|
169
|
-
getNodeElement,
|
|
170
|
-
getNodeElementForNode,
|
|
171
|
-
getScrollLeft,
|
|
172
|
-
getTree,
|
|
173
|
-
onCanMove,
|
|
174
|
-
onCanMoveTo,
|
|
175
|
-
onDragMove,
|
|
176
|
-
onDragStop,
|
|
177
|
-
onIsMoveHandle,
|
|
178
|
-
openFolderDelay,
|
|
179
|
-
openNode,
|
|
180
|
-
refreshElements,
|
|
181
|
-
slide,
|
|
182
|
-
treeElement,
|
|
183
|
-
triggerEvent,
|
|
184
|
-
});
|
|
118
|
+
const newNode = existingNode.addParent(newNodeInfo);
|
|
185
119
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
isFocusOnTree,
|
|
190
|
-
keyboardSupport,
|
|
191
|
-
openNode,
|
|
192
|
-
selectNode,
|
|
193
|
-
});
|
|
120
|
+
if (newNode) {
|
|
121
|
+
this.refreshElements(newNode.parent);
|
|
122
|
+
}
|
|
194
123
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
autoEscape,
|
|
198
|
-
buttonLeft,
|
|
199
|
-
closedIcon,
|
|
200
|
-
dragAndDrop,
|
|
201
|
-
getTree,
|
|
202
|
-
isNodeSelected,
|
|
203
|
-
onCreateLi,
|
|
204
|
-
openedIcon,
|
|
205
|
-
rtl,
|
|
206
|
-
showEmptyFolder,
|
|
207
|
-
tabIndex,
|
|
208
|
-
});
|
|
124
|
+
return newNode;
|
|
125
|
+
}
|
|
209
126
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const onMouseStop = this.mouseStop.bind(this);
|
|
127
|
+
public addToSelection(node?: Node, mustSetFocus?: boolean): JQuery {
|
|
128
|
+
if (!node) {
|
|
129
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
130
|
+
}
|
|
215
131
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
getMouseDelay,
|
|
219
|
-
getNode,
|
|
220
|
-
onClickButton: this.toggle.bind(this),
|
|
221
|
-
onClickTitle: this.doSelectNode.bind(this),
|
|
222
|
-
onMouseCapture,
|
|
223
|
-
onMouseDrag,
|
|
224
|
-
onMouseStart,
|
|
225
|
-
onMouseStop,
|
|
226
|
-
triggerEvent,
|
|
227
|
-
useContextMenu: this.options.useContextMenu,
|
|
228
|
-
});
|
|
132
|
+
this.selectNodeHandler.addToSelection(node);
|
|
133
|
+
this.openParents(node);
|
|
229
134
|
|
|
230
|
-
this.
|
|
231
|
-
this.dndHandler = dndHandler;
|
|
232
|
-
this.keyHandler = keyHandler;
|
|
233
|
-
this.mouseHandler = mouseHandler;
|
|
234
|
-
this.renderer = renderer;
|
|
235
|
-
this.saveStateHandler = saveStateHandler;
|
|
236
|
-
this.scrollHandler = scrollHandler;
|
|
237
|
-
this.selectNodeHandler = selectNodeHandler;
|
|
238
|
-
}
|
|
135
|
+
this.getNodeElementForNode(node).select(mustSetFocus ?? true);
|
|
239
136
|
|
|
240
|
-
|
|
241
|
-
const node = this.getNode(element);
|
|
137
|
+
this.saveState();
|
|
242
138
|
|
|
243
|
-
return
|
|
139
|
+
return this.element;
|
|
244
140
|
}
|
|
245
141
|
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
const getScrollLeft = this.scrollHandler.getScrollLeft.bind(
|
|
249
|
-
this.scrollHandler,
|
|
250
|
-
);
|
|
251
|
-
const openedIconElement = this.renderer.openedIconElement;
|
|
252
|
-
const tabIndex = this.options.tabIndex;
|
|
253
|
-
const $treeElement = this.element;
|
|
254
|
-
const triggerEvent = this.triggerEvent.bind(this);
|
|
142
|
+
public appendNode(newNodeInfo: NodeData, parentNodeParam?: Node): Node {
|
|
143
|
+
const parentNode = parentNodeParam ?? this.tree;
|
|
255
144
|
|
|
256
|
-
|
|
257
|
-
$treeElement,
|
|
258
|
-
closedIconElement,
|
|
259
|
-
getScrollLeft,
|
|
260
|
-
node,
|
|
261
|
-
openedIconElement,
|
|
262
|
-
tabIndex,
|
|
263
|
-
triggerEvent,
|
|
264
|
-
});
|
|
265
|
-
}
|
|
145
|
+
const node = parentNode.append(newNodeInfo);
|
|
266
146
|
|
|
267
|
-
|
|
268
|
-
const getScrollLeft = this.scrollHandler.getScrollLeft.bind(
|
|
269
|
-
this.scrollHandler,
|
|
270
|
-
);
|
|
271
|
-
const tabIndex = this.options.tabIndex;
|
|
272
|
-
const $treeElement = this.element;
|
|
147
|
+
this.refreshElements(parentNode);
|
|
273
148
|
|
|
274
|
-
return
|
|
275
|
-
$treeElement,
|
|
276
|
-
getScrollLeft,
|
|
277
|
-
node,
|
|
278
|
-
tabIndex,
|
|
279
|
-
});
|
|
149
|
+
return node;
|
|
280
150
|
}
|
|
281
151
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
this.removeFromSelection(node);
|
|
152
|
+
public closeNode(node?: Node, slideParam?: boolean | null): JQuery {
|
|
153
|
+
if (!node) {
|
|
154
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
286
155
|
}
|
|
287
|
-
}
|
|
288
156
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
157
|
+
const slide = slideParam ?? this.options.slide;
|
|
158
|
+
|
|
159
|
+
if (node.isFolder() || node.isEmptyFolder) {
|
|
160
|
+
this.createFolderElement(node).close(
|
|
161
|
+
slide,
|
|
162
|
+
this.options.animationSpeed,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
this.saveState();
|
|
294
166
|
}
|
|
167
|
+
|
|
168
|
+
return this.element;
|
|
295
169
|
}
|
|
296
170
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.deselectNodes(parentNode);
|
|
301
|
-
this.loadSubtree(data, parentNode);
|
|
302
|
-
} else {
|
|
303
|
-
this.initTree(data);
|
|
304
|
-
}
|
|
171
|
+
public deinit(): void {
|
|
172
|
+
this.element.empty();
|
|
173
|
+
this.element.off();
|
|
305
174
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
}
|
|
175
|
+
this.keyHandler.deinit();
|
|
176
|
+
this.mouseHandler.deinit();
|
|
310
177
|
|
|
311
|
-
this.
|
|
312
|
-
parent_node: parentNode,
|
|
313
|
-
tree_data: data,
|
|
314
|
-
});
|
|
315
|
-
}
|
|
178
|
+
this.tree = new Node({}, true);
|
|
316
179
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
parentNode: Node | null,
|
|
320
|
-
onFinished: HandleFinishedLoading | null,
|
|
321
|
-
): void {
|
|
322
|
-
const urlInfo = urlInfoParam ?? this.getDataUrlInfo(parentNode);
|
|
180
|
+
super.deinit();
|
|
181
|
+
}
|
|
323
182
|
|
|
324
|
-
|
|
183
|
+
public getNodeByCallback(callback: (node: Node) => boolean): Node | null {
|
|
184
|
+
return this.tree.getNodeByCallback(callback);
|
|
325
185
|
}
|
|
326
186
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
335
|
-
};
|
|
187
|
+
public getNodeByHtmlElement(
|
|
188
|
+
inputElement: HTMLElement | JQuery,
|
|
189
|
+
): Node | null {
|
|
190
|
+
const element =
|
|
191
|
+
inputElement instanceof HTMLElement
|
|
192
|
+
? inputElement
|
|
193
|
+
: inputElement[0];
|
|
336
194
|
|
|
337
|
-
if (!
|
|
338
|
-
|
|
339
|
-
this.deselectCurrentNode();
|
|
340
|
-
saveState();
|
|
341
|
-
return;
|
|
195
|
+
if (!element) {
|
|
196
|
+
return null;
|
|
342
197
|
}
|
|
343
|
-
const defaultOptions = { mustSetFocus: true, mustToggle: true };
|
|
344
|
-
const selectOptions = { ...defaultOptions, ...(optionsParam ?? {}) };
|
|
345
|
-
|
|
346
|
-
const canSelect = (): boolean => {
|
|
347
|
-
if (this.options.onCanSelectNode) {
|
|
348
|
-
return (
|
|
349
|
-
this.options.selectable &&
|
|
350
|
-
this.options.onCanSelectNode(node)
|
|
351
|
-
);
|
|
352
|
-
} else {
|
|
353
|
-
return this.options.selectable;
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
198
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
199
|
+
return this.getNode(element);
|
|
200
|
+
}
|
|
360
201
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
this.triggerEvent("tree.select", {
|
|
365
|
-
node: null,
|
|
366
|
-
previous_node: node,
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
} else {
|
|
370
|
-
const deselectedNode = this.getSelectedNode() || null;
|
|
371
|
-
this.deselectCurrentNode();
|
|
372
|
-
this.addToSelection(node, selectOptions.mustSetFocus);
|
|
202
|
+
public getNodeById(nodeId: NodeId): Node | null {
|
|
203
|
+
return this.tree.getNodeById(nodeId);
|
|
204
|
+
}
|
|
373
205
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
});
|
|
378
|
-
this.openParents(node);
|
|
379
|
-
}
|
|
206
|
+
public getNodeByName(name: string): Node | null {
|
|
207
|
+
return this.tree.getNodeByName(name);
|
|
208
|
+
}
|
|
380
209
|
|
|
381
|
-
|
|
210
|
+
public getNodeByNameMustExist(name: string): Node {
|
|
211
|
+
return this.tree.getNodeByNameMustExist(name);
|
|
382
212
|
}
|
|
383
213
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return -1;
|
|
387
|
-
} else if (typeof this.options.autoOpen === "number") {
|
|
388
|
-
return this.options.autoOpen;
|
|
389
|
-
} else if (typeof this.options.autoOpen === "string") {
|
|
390
|
-
return parseInt(this.options.autoOpen, 10);
|
|
391
|
-
} else {
|
|
392
|
-
return 0;
|
|
393
|
-
}
|
|
214
|
+
public getNodesByProperty(key: string, value: unknown): Node[] {
|
|
215
|
+
return this.tree.getNodesByProperty(key, value);
|
|
394
216
|
}
|
|
395
217
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
218
|
+
public getSelectedNode(): false | Node {
|
|
219
|
+
return this.selectNodeHandler.getSelectedNode();
|
|
220
|
+
}
|
|
399
221
|
|
|
400
|
-
|
|
401
|
-
|
|
222
|
+
public getSelectedNodes(): Node[] {
|
|
223
|
+
return this.selectNodeHandler.getSelectedNodes();
|
|
224
|
+
}
|
|
402
225
|
|
|
403
|
-
|
|
226
|
+
public getState(): null | SavedState {
|
|
227
|
+
return this.saveStateHandler.getState();
|
|
228
|
+
}
|
|
404
229
|
|
|
405
|
-
|
|
406
|
-
|
|
230
|
+
public getStateFromStorage(): null | SavedState {
|
|
231
|
+
return this.saveStateHandler.getStateFromStorage();
|
|
232
|
+
}
|
|
407
233
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const data = { node: node.id };
|
|
412
|
-
urlInfo.data = data;
|
|
413
|
-
} else {
|
|
414
|
-
// Add selected_node parameter
|
|
415
|
-
const selectedNodeId = this.getNodeIdToBeSelected();
|
|
416
|
-
if (selectedNodeId) {
|
|
417
|
-
const data = { selected_node: selectedNodeId };
|
|
418
|
-
urlInfo.data = data;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
};
|
|
234
|
+
public getTree(): Node {
|
|
235
|
+
return this.tree;
|
|
236
|
+
}
|
|
422
237
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
} else if (typeof dataUrl === "string") {
|
|
426
|
-
return getUrlFromString(dataUrl);
|
|
427
|
-
} else if (dataUrl && typeof dataUrl === "object") {
|
|
428
|
-
setUrlInfoData(dataUrl);
|
|
429
|
-
return dataUrl;
|
|
430
|
-
} else {
|
|
431
|
-
return null;
|
|
432
|
-
}
|
|
238
|
+
public getVersion(): string {
|
|
239
|
+
return __version__;
|
|
433
240
|
}
|
|
434
241
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
242
|
+
public init(): void {
|
|
243
|
+
super.init();
|
|
244
|
+
|
|
245
|
+
this.element = this.$el;
|
|
246
|
+
this.isInitialized = false;
|
|
247
|
+
|
|
248
|
+
this.options.rtl = this.getRtlOption();
|
|
249
|
+
|
|
250
|
+
if (this.options.closedIcon == null) {
|
|
251
|
+
this.options.closedIcon = this.getDefaultClosedIcon();
|
|
442
252
|
}
|
|
253
|
+
|
|
254
|
+
this.connectHandlers();
|
|
255
|
+
|
|
256
|
+
this.initData();
|
|
443
257
|
}
|
|
444
258
|
|
|
445
|
-
|
|
446
|
-
|
|
259
|
+
public isDragging(): boolean {
|
|
260
|
+
return this.dndHandler.isDragging;
|
|
261
|
+
}
|
|
447
262
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return null;
|
|
263
|
+
public isNodeSelected(node?: Node): boolean {
|
|
264
|
+
if (!node) {
|
|
265
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
452
266
|
}
|
|
267
|
+
|
|
268
|
+
return this.selectNodeHandler.isNodeSelected(node);
|
|
453
269
|
}
|
|
454
270
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
return this.getNodeElementForNode(node);
|
|
459
|
-
} else {
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
271
|
+
public loadData(data: NodeData[], parentNode: Node | null): JQuery {
|
|
272
|
+
this.doLoadData(data, parentNode);
|
|
273
|
+
return this.element;
|
|
462
274
|
}
|
|
463
275
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
276
|
+
/*
|
|
277
|
+
signatures:
|
|
278
|
+
- loadDataFromUrl(url, parent_node=null, on_finished=null)
|
|
279
|
+
loadDataFromUrl('/my_data');
|
|
280
|
+
loadDataFromUrl('/my_data', node1);
|
|
281
|
+
loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
|
|
282
|
+
loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
|
|
283
|
+
|
|
284
|
+
- loadDataFromUrl(parent_node=null, on_finished=null)
|
|
285
|
+
loadDataFromUrl();
|
|
286
|
+
loadDataFromUrl(node1);
|
|
287
|
+
loadDataFromUrl(null, function() { console.log('finished'); });
|
|
288
|
+
loadDataFromUrl(node1, function() { console.log('finished'); });
|
|
289
|
+
*/
|
|
290
|
+
public loadDataFromUrl(
|
|
291
|
+
param1: Node | null | string,
|
|
292
|
+
param2?: HandleFinishedLoading | Node | null,
|
|
293
|
+
param3?: HandleFinishedLoading,
|
|
294
|
+
): JQuery {
|
|
295
|
+
if (typeof param1 === "string") {
|
|
296
|
+
// first parameter is url
|
|
297
|
+
this.doLoadDataFromUrl(
|
|
298
|
+
param1,
|
|
299
|
+
param2 as Node | null,
|
|
300
|
+
param3 ?? null,
|
|
301
|
+
);
|
|
467
302
|
} else {
|
|
468
|
-
|
|
303
|
+
// first parameter is not url
|
|
304
|
+
this.doLoadDataFromUrl(
|
|
305
|
+
null,
|
|
306
|
+
param1,
|
|
307
|
+
param2 as HandleFinishedLoading | null,
|
|
308
|
+
);
|
|
469
309
|
}
|
|
310
|
+
|
|
311
|
+
return this.element;
|
|
470
312
|
}
|
|
471
313
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
return null;
|
|
314
|
+
public moveDown(): JQuery {
|
|
315
|
+
const selectedNode = this.getSelectedNode();
|
|
316
|
+
if (selectedNode) {
|
|
317
|
+
this.keyHandler.moveDown(selectedNode);
|
|
477
318
|
}
|
|
319
|
+
|
|
320
|
+
return this.element;
|
|
478
321
|
}
|
|
479
322
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
dataRtl !== null &&
|
|
488
|
-
dataRtl !== false &&
|
|
489
|
-
dataRtl !== undefined
|
|
490
|
-
) {
|
|
491
|
-
return true;
|
|
492
|
-
} else {
|
|
493
|
-
return false;
|
|
494
|
-
}
|
|
323
|
+
public moveNode(
|
|
324
|
+
node?: Node,
|
|
325
|
+
targetNode?: Node,
|
|
326
|
+
position?: Position,
|
|
327
|
+
): JQuery {
|
|
328
|
+
if (!node) {
|
|
329
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
495
330
|
}
|
|
496
|
-
}
|
|
497
331
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
this.doLoadData(this.options.data, null);
|
|
501
|
-
} else {
|
|
502
|
-
const dataUrl = this.getDataUrlInfo(null);
|
|
503
|
-
|
|
504
|
-
if (dataUrl) {
|
|
505
|
-
this.doLoadDataFromUrl(null, null, null);
|
|
506
|
-
} else {
|
|
507
|
-
this.doLoadData([], null);
|
|
508
|
-
}
|
|
332
|
+
if (!targetNode) {
|
|
333
|
+
throw Error(PARAM_IS_EMPTY + "targetNode");
|
|
509
334
|
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
private initTree(data: NodeData[]): void {
|
|
513
|
-
const doInit = (): void => {
|
|
514
|
-
if (!this.isInitialized) {
|
|
515
|
-
this.isInitialized = true;
|
|
516
|
-
this.triggerEvent("tree.init");
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
335
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
this.options.nodeClass,
|
|
524
|
-
);
|
|
336
|
+
if (!position) {
|
|
337
|
+
throw Error(PARAM_IS_EMPTY + "position");
|
|
338
|
+
}
|
|
525
339
|
|
|
526
|
-
this.
|
|
340
|
+
this.tree.moveNode(node, targetNode, position);
|
|
341
|
+
this.refreshElements(null);
|
|
527
342
|
|
|
528
|
-
this.
|
|
343
|
+
return this.element;
|
|
344
|
+
}
|
|
529
345
|
|
|
530
|
-
|
|
346
|
+
public moveUp(): JQuery {
|
|
347
|
+
const selectedNode = this.getSelectedNode();
|
|
348
|
+
if (selectedNode) {
|
|
349
|
+
this.keyHandler.moveUp(selectedNode);
|
|
350
|
+
}
|
|
531
351
|
|
|
532
|
-
this.
|
|
352
|
+
return this.element;
|
|
353
|
+
}
|
|
533
354
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
355
|
+
public openNode(
|
|
356
|
+
node?: Node,
|
|
357
|
+
param1?: boolean | OnFinishOpenNode,
|
|
358
|
+
param2?: OnFinishOpenNode,
|
|
359
|
+
): JQuery {
|
|
360
|
+
if (!node) {
|
|
361
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
539
362
|
}
|
|
540
|
-
}
|
|
541
363
|
|
|
542
|
-
|
|
543
|
-
|
|
364
|
+
const parseParams = (): [boolean, OnFinishOpenNode | undefined] => {
|
|
365
|
+
let onFinished: null | OnFinishOpenNode;
|
|
366
|
+
let slide: boolean | null;
|
|
544
367
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
368
|
+
if (isFunction(param1)) {
|
|
369
|
+
onFinished = param1 as OnFinishOpenNode;
|
|
370
|
+
slide = null;
|
|
371
|
+
} else {
|
|
372
|
+
slide = param1 as boolean;
|
|
373
|
+
onFinished = param2 as OnFinishOpenNode;
|
|
374
|
+
}
|
|
551
375
|
|
|
552
|
-
|
|
553
|
-
|
|
376
|
+
if (slide == null) {
|
|
377
|
+
slide = this.options.slide;
|
|
378
|
+
}
|
|
554
379
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
} else {
|
|
558
|
-
return subtree === selectedNode || subtree.isParentOf(selectedNode);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
380
|
+
return [slide, onFinished];
|
|
381
|
+
};
|
|
561
382
|
|
|
562
|
-
|
|
563
|
-
node: Node,
|
|
564
|
-
slide = true,
|
|
565
|
-
onFinished?: OnFinishOpenNode,
|
|
566
|
-
): void {
|
|
567
|
-
node.is_loading = true;
|
|
383
|
+
const [slide, onFinished] = parseParams();
|
|
568
384
|
|
|
569
|
-
this.
|
|
570
|
-
|
|
571
|
-
});
|
|
385
|
+
this.openNodeInternal(node, slide, onFinished);
|
|
386
|
+
return this.element;
|
|
572
387
|
}
|
|
573
388
|
|
|
574
|
-
|
|
575
|
-
parentNode.
|
|
389
|
+
public prependNode(newNodeInfo: NodeData, parentNodeParam?: Node): Node {
|
|
390
|
+
const parentNode = parentNodeParam ?? this.tree;
|
|
576
391
|
|
|
577
|
-
|
|
578
|
-
parentNode.is_loading = false;
|
|
392
|
+
const node = parentNode.prepend(newNodeInfo);
|
|
579
393
|
|
|
580
394
|
this.refreshElements(parentNode);
|
|
581
|
-
}
|
|
582
395
|
|
|
583
|
-
|
|
584
|
-
if (this.options.dragAndDrop) {
|
|
585
|
-
return this.dndHandler.mouseCapture(positionInfo);
|
|
586
|
-
} else {
|
|
587
|
-
return false;
|
|
588
|
-
}
|
|
396
|
+
return node;
|
|
589
397
|
}
|
|
590
398
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
this.scrollHandler.checkScrolling(positionInfo);
|
|
596
|
-
return result;
|
|
597
|
-
} else {
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
399
|
+
public refresh(): JQuery {
|
|
400
|
+
this.refreshElements(null);
|
|
401
|
+
return this.element;
|
|
600
402
|
}
|
|
601
403
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
} else {
|
|
606
|
-
return false;
|
|
607
|
-
}
|
|
404
|
+
public refreshHitAreas(): JQuery {
|
|
405
|
+
this.dndHandler.refresh();
|
|
406
|
+
return this.element;
|
|
608
407
|
}
|
|
609
408
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
return this.dndHandler.mouseStop(positionInfo);
|
|
614
|
-
} else {
|
|
615
|
-
return false;
|
|
616
|
-
}
|
|
409
|
+
public reload(onFinished: HandleFinishedLoading | null): JQuery {
|
|
410
|
+
this.doLoadDataFromUrl(null, null, onFinished);
|
|
411
|
+
return this.element;
|
|
617
412
|
}
|
|
618
413
|
|
|
619
|
-
|
|
620
|
-
node
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
): void {
|
|
624
|
-
const doOpenNode = (
|
|
625
|
-
_node: Node,
|
|
626
|
-
_slide: boolean,
|
|
627
|
-
_onFinished?: OnFinishOpenNode,
|
|
628
|
-
): void => {
|
|
629
|
-
const folderElement = this.createFolderElement(_node);
|
|
630
|
-
folderElement.open(
|
|
631
|
-
_onFinished,
|
|
632
|
-
_slide,
|
|
633
|
-
this.options.animationSpeed,
|
|
634
|
-
);
|
|
635
|
-
};
|
|
414
|
+
public removeFromSelection(node?: Node): JQuery {
|
|
415
|
+
if (!node) {
|
|
416
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
417
|
+
}
|
|
636
418
|
|
|
637
|
-
|
|
638
|
-
if (node.load_on_demand) {
|
|
639
|
-
this.loadFolderOnDemand(node, slide, onFinished);
|
|
640
|
-
} else {
|
|
641
|
-
let parent = node.parent;
|
|
419
|
+
this.selectNodeHandler.removeFromSelection(node);
|
|
642
420
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
if (parent.parent) {
|
|
646
|
-
doOpenNode(parent, false);
|
|
647
|
-
}
|
|
648
|
-
parent = parent.parent;
|
|
649
|
-
}
|
|
421
|
+
this.getNodeElementForNode(node).deselect();
|
|
422
|
+
this.saveState();
|
|
650
423
|
|
|
651
|
-
|
|
652
|
-
this.saveState();
|
|
653
|
-
}
|
|
654
|
-
}
|
|
424
|
+
return this.element;
|
|
655
425
|
}
|
|
656
426
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
if (parent?.parent && !parent.is_open) {
|
|
661
|
-
this.openNode(parent, false);
|
|
427
|
+
public removeNode(node?: Node): JQuery {
|
|
428
|
+
if (!node) {
|
|
429
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
662
430
|
}
|
|
663
|
-
}
|
|
664
431
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
*/
|
|
669
|
-
private refreshElements(fromNode: Node | null): void {
|
|
670
|
-
const mustSetFocus = this.isFocusOnTree();
|
|
671
|
-
const mustSelect = fromNode
|
|
672
|
-
? this.isSelectedNodeInSubtree(fromNode)
|
|
673
|
-
: false;
|
|
432
|
+
if (!node.parent) {
|
|
433
|
+
throw Error("Node has no parent");
|
|
434
|
+
}
|
|
674
435
|
|
|
675
|
-
this.
|
|
436
|
+
this.selectNodeHandler.removeFromSelection(node, true); // including children
|
|
676
437
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
438
|
+
const parent = node.parent;
|
|
439
|
+
node.remove();
|
|
440
|
+
this.refreshElements(parent);
|
|
680
441
|
|
|
681
|
-
this.
|
|
442
|
+
return this.element;
|
|
682
443
|
}
|
|
683
444
|
|
|
684
|
-
|
|
685
|
-
if (
|
|
686
|
-
|
|
445
|
+
public scrollToNode(node?: Node): JQuery {
|
|
446
|
+
if (!node) {
|
|
447
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
687
448
|
}
|
|
688
|
-
}
|
|
689
449
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (node) {
|
|
693
|
-
const nodeElement = this.getNodeElementForNode(node);
|
|
694
|
-
nodeElement.select(mustSetFocus);
|
|
450
|
+
if (!node.element) {
|
|
451
|
+
return this.element;
|
|
695
452
|
}
|
|
453
|
+
|
|
454
|
+
const top =
|
|
455
|
+
getOffsetTop(node.element) -
|
|
456
|
+
getOffsetTop(this.$el.get(0) as HTMLElement);
|
|
457
|
+
|
|
458
|
+
this.scrollHandler.scrollToY(top);
|
|
459
|
+
|
|
460
|
+
return this.element;
|
|
696
461
|
}
|
|
697
462
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
} else {
|
|
706
|
-
const state = this.saveStateHandler.getStateFromStorage();
|
|
463
|
+
public selectNode(
|
|
464
|
+
node: Node | null,
|
|
465
|
+
optionsParam?: SelectNodeOptions,
|
|
466
|
+
): JQuery {
|
|
467
|
+
this.doSelectNode(node, optionsParam);
|
|
468
|
+
return this.element;
|
|
469
|
+
}
|
|
707
470
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
this.saveStateHandler.setInitialState(state);
|
|
471
|
+
public setOption(option: string, value: unknown): JQuery {
|
|
472
|
+
(this.options as unknown as Record<string, unknown>)[option] = value;
|
|
473
|
+
return this.element;
|
|
474
|
+
}
|
|
713
475
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
476
|
+
public setState(state?: SavedState): JQuery {
|
|
477
|
+
if (state) {
|
|
478
|
+
this.saveStateHandler.setInitialState(state);
|
|
479
|
+
this.refreshElements(null);
|
|
480
|
+
}
|
|
719
481
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
if (this.options.autoOpen === false) {
|
|
723
|
-
return false;
|
|
724
|
-
}
|
|
482
|
+
return this.element;
|
|
483
|
+
}
|
|
725
484
|
|
|
726
|
-
|
|
727
|
-
|
|
485
|
+
public toggle(node?: Node, slideParam: boolean | null = null): JQuery {
|
|
486
|
+
if (!node) {
|
|
487
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
488
|
+
}
|
|
728
489
|
|
|
729
|
-
|
|
730
|
-
if (node.load_on_demand) {
|
|
731
|
-
mustLoadOnDemand = true;
|
|
732
|
-
return false;
|
|
733
|
-
} else if (!node.hasChildren()) {
|
|
734
|
-
return false;
|
|
735
|
-
} else {
|
|
736
|
-
node.is_open = true;
|
|
737
|
-
return level !== maxLevel;
|
|
738
|
-
}
|
|
739
|
-
});
|
|
490
|
+
const slide = slideParam ?? this.options.slide;
|
|
740
491
|
|
|
741
|
-
|
|
742
|
-
|
|
492
|
+
if (node.is_open) {
|
|
493
|
+
this.closeNode(node, slide);
|
|
494
|
+
} else {
|
|
495
|
+
this.openNode(node, slide);
|
|
496
|
+
}
|
|
743
497
|
|
|
744
|
-
|
|
498
|
+
return this.element;
|
|
499
|
+
}
|
|
745
500
|
|
|
746
|
-
|
|
747
|
-
|
|
501
|
+
public toJson(): string {
|
|
502
|
+
return JSON.stringify(this.tree.getData());
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
public updateNode(node?: Node, data?: NodeData): JQuery {
|
|
506
|
+
if (!node) {
|
|
507
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
748
508
|
}
|
|
749
509
|
|
|
750
|
-
|
|
751
|
-
|
|
510
|
+
if (!data) {
|
|
511
|
+
return this.element;
|
|
512
|
+
}
|
|
752
513
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
private setInitialStateOnDemand(cbFinished: () => void): void {
|
|
756
|
-
const restoreState = (): boolean => {
|
|
757
|
-
if (!this.options.saveState) {
|
|
758
|
-
return false;
|
|
759
|
-
} else {
|
|
760
|
-
const state = this.saveStateHandler.getStateFromStorage();
|
|
514
|
+
const idIsChanged =
|
|
515
|
+
typeof data === "object" && data.id && data.id !== node.id;
|
|
761
516
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
this.saveStateHandler.setInitialStateOnDemand(
|
|
766
|
-
state,
|
|
767
|
-
cbFinished,
|
|
768
|
-
);
|
|
517
|
+
if (idIsChanged) {
|
|
518
|
+
this.tree.removeNodeFromIndex(node);
|
|
519
|
+
}
|
|
769
520
|
|
|
770
|
-
|
|
771
|
-
|
|
521
|
+
node.setData(data);
|
|
522
|
+
|
|
523
|
+
if (idIsChanged) {
|
|
524
|
+
this.tree.addNodeToIndex(node);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (
|
|
528
|
+
typeof data === "object" &&
|
|
529
|
+
data.children &&
|
|
530
|
+
data.children instanceof Array
|
|
531
|
+
) {
|
|
532
|
+
node.removeChildren();
|
|
533
|
+
|
|
534
|
+
if (data.children.length) {
|
|
535
|
+
node.loadFromData(data.children as Node[]);
|
|
772
536
|
}
|
|
773
|
-
}
|
|
537
|
+
}
|
|
774
538
|
|
|
775
|
-
|
|
776
|
-
const maxLevel = this.getAutoOpenMaxLevel();
|
|
777
|
-
let loadingCount = 0;
|
|
539
|
+
this.refreshElements(node);
|
|
778
540
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
this.openNodeInternal(node, false, () => {
|
|
782
|
-
loadingCount -= 1;
|
|
783
|
-
openNodes();
|
|
784
|
-
});
|
|
785
|
-
};
|
|
541
|
+
return this.element;
|
|
542
|
+
}
|
|
786
543
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
544
|
+
private connectHandlers() {
|
|
545
|
+
const {
|
|
546
|
+
autoEscape,
|
|
547
|
+
buttonLeft,
|
|
548
|
+
closedIcon,
|
|
549
|
+
dataFilter,
|
|
550
|
+
dragAndDrop,
|
|
551
|
+
keyboardSupport,
|
|
552
|
+
onCanMove,
|
|
553
|
+
onCanMoveTo,
|
|
554
|
+
onCreateLi,
|
|
555
|
+
onDragMove,
|
|
556
|
+
onDragStop,
|
|
557
|
+
onGetStateFromStorage,
|
|
558
|
+
onIsMoveHandle,
|
|
559
|
+
onLoadFailed,
|
|
560
|
+
onLoading,
|
|
561
|
+
onSetStateFromStorage,
|
|
562
|
+
openedIcon,
|
|
563
|
+
openFolderDelay,
|
|
564
|
+
rtl,
|
|
565
|
+
saveState,
|
|
566
|
+
showEmptyFolder,
|
|
567
|
+
slide,
|
|
568
|
+
tabIndex,
|
|
569
|
+
} = this.options;
|
|
793
570
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
571
|
+
const closeNode = this.closeNode.bind(this);
|
|
572
|
+
const getNodeElement = this.getNodeElement.bind(this);
|
|
573
|
+
const getNodeElementForNode = this.getNodeElementForNode.bind(this);
|
|
574
|
+
const getNodeById = this.getNodeById.bind(this);
|
|
575
|
+
const getSelectedNode = this.getSelectedNode.bind(this);
|
|
576
|
+
const getTree = this.getTree.bind(this);
|
|
577
|
+
const isFocusOnTree = this.isFocusOnTree.bind(this);
|
|
578
|
+
const loadData = this.loadData.bind(this);
|
|
579
|
+
const openNode = this.openNodeInternal.bind(this);
|
|
580
|
+
const refreshElements = this.refreshElements.bind(this);
|
|
581
|
+
const refreshHitAreas = this.refreshHitAreas.bind(this);
|
|
582
|
+
const selectNode = this.selectNode.bind(this);
|
|
583
|
+
const $treeElement = this.element;
|
|
584
|
+
const treeElement = this.element.get(0) as HTMLElement;
|
|
585
|
+
const triggerEvent = this.triggerEvent.bind(this);
|
|
797
586
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
587
|
+
const selectNodeHandler = new SelectNodeHandler({
|
|
588
|
+
getNodeById,
|
|
589
|
+
});
|
|
801
590
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
591
|
+
const addToSelection =
|
|
592
|
+
selectNodeHandler.addToSelection.bind(selectNodeHandler);
|
|
593
|
+
const getSelectedNodes =
|
|
594
|
+
selectNodeHandler.getSelectedNodes.bind(selectNodeHandler);
|
|
595
|
+
const isNodeSelected =
|
|
596
|
+
selectNodeHandler.isNodeSelected.bind(selectNodeHandler);
|
|
597
|
+
const removeFromSelection =
|
|
598
|
+
selectNodeHandler.removeFromSelection.bind(selectNodeHandler);
|
|
599
|
+
const getMouseDelay = () => this.options.startDndDelay ?? 0;
|
|
806
600
|
|
|
807
|
-
|
|
808
|
-
|
|
601
|
+
const dataLoader = new DataLoader({
|
|
602
|
+
dataFilter,
|
|
603
|
+
loadData,
|
|
604
|
+
onLoadFailed,
|
|
605
|
+
onLoading,
|
|
606
|
+
treeElement,
|
|
607
|
+
triggerEvent,
|
|
608
|
+
});
|
|
809
609
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
610
|
+
const saveStateHandler = new SaveStateHandler({
|
|
611
|
+
addToSelection,
|
|
612
|
+
getNodeById,
|
|
613
|
+
getSelectedNodes,
|
|
614
|
+
getTree,
|
|
615
|
+
onGetStateFromStorage,
|
|
616
|
+
onSetStateFromStorage,
|
|
617
|
+
openNode,
|
|
618
|
+
refreshElements,
|
|
619
|
+
removeFromSelection,
|
|
620
|
+
saveState,
|
|
621
|
+
});
|
|
814
622
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const event = jQuery.Event(eventName, values);
|
|
820
|
-
this.element.trigger(event);
|
|
821
|
-
return event;
|
|
822
|
-
}
|
|
623
|
+
const scrollHandler = new ScrollHandler({
|
|
624
|
+
refreshHitAreas,
|
|
625
|
+
treeElement,
|
|
626
|
+
});
|
|
823
627
|
|
|
824
|
-
|
|
825
|
-
newNodeInfo: NodeData,
|
|
826
|
-
existingNode: Node,
|
|
827
|
-
): Node | null {
|
|
828
|
-
const newNode = existingNode.addAfter(newNodeInfo);
|
|
628
|
+
const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);
|
|
829
629
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
630
|
+
const dndHandler = new DragAndDropHandler({
|
|
631
|
+
autoEscape,
|
|
632
|
+
getNodeElement,
|
|
633
|
+
getNodeElementForNode,
|
|
634
|
+
getScrollLeft,
|
|
635
|
+
getTree,
|
|
636
|
+
onCanMove,
|
|
637
|
+
onCanMoveTo,
|
|
638
|
+
onDragMove,
|
|
639
|
+
onDragStop,
|
|
640
|
+
onIsMoveHandle,
|
|
641
|
+
openFolderDelay,
|
|
642
|
+
openNode,
|
|
643
|
+
refreshElements,
|
|
644
|
+
slide,
|
|
645
|
+
treeElement,
|
|
646
|
+
triggerEvent,
|
|
647
|
+
});
|
|
833
648
|
|
|
834
|
-
|
|
835
|
-
|
|
649
|
+
const keyHandler = new KeyHandler({
|
|
650
|
+
closeNode,
|
|
651
|
+
getSelectedNode,
|
|
652
|
+
isFocusOnTree,
|
|
653
|
+
keyboardSupport,
|
|
654
|
+
openNode,
|
|
655
|
+
selectNode,
|
|
656
|
+
});
|
|
836
657
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
658
|
+
const renderer = new ElementsRenderer({
|
|
659
|
+
$element: $treeElement,
|
|
660
|
+
autoEscape,
|
|
661
|
+
buttonLeft,
|
|
662
|
+
closedIcon,
|
|
663
|
+
dragAndDrop,
|
|
664
|
+
getTree,
|
|
665
|
+
isNodeSelected,
|
|
666
|
+
onCreateLi,
|
|
667
|
+
openedIcon,
|
|
668
|
+
rtl,
|
|
669
|
+
showEmptyFolder,
|
|
670
|
+
tabIndex,
|
|
671
|
+
});
|
|
844
672
|
|
|
845
|
-
const
|
|
673
|
+
const getNode = this.getNode.bind(this);
|
|
674
|
+
const onMouseCapture = this.mouseCapture.bind(this);
|
|
675
|
+
const onMouseDrag = this.mouseDrag.bind(this);
|
|
676
|
+
const onMouseStart = this.mouseStart.bind(this);
|
|
677
|
+
const onMouseStop = this.mouseStop.bind(this);
|
|
678
|
+
|
|
679
|
+
const mouseHandler = new MouseHandler({
|
|
680
|
+
element: treeElement,
|
|
681
|
+
getMouseDelay,
|
|
682
|
+
getNode,
|
|
683
|
+
onClickButton: this.toggle.bind(this),
|
|
684
|
+
onClickTitle: this.doSelectNode.bind(this),
|
|
685
|
+
onMouseCapture,
|
|
686
|
+
onMouseDrag,
|
|
687
|
+
onMouseStart,
|
|
688
|
+
onMouseStop,
|
|
689
|
+
triggerEvent,
|
|
690
|
+
useContextMenu: this.options.useContextMenu,
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
this.dataLoader = dataLoader;
|
|
694
|
+
this.dndHandler = dndHandler;
|
|
695
|
+
this.keyHandler = keyHandler;
|
|
696
|
+
this.mouseHandler = mouseHandler;
|
|
697
|
+
this.renderer = renderer;
|
|
698
|
+
this.saveStateHandler = saveStateHandler;
|
|
699
|
+
this.scrollHandler = scrollHandler;
|
|
700
|
+
this.selectNodeHandler = selectNodeHandler;
|
|
701
|
+
}
|
|
846
702
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
}
|
|
703
|
+
private containsElement(element: HTMLElement): boolean {
|
|
704
|
+
const node = this.getNode(element);
|
|
850
705
|
|
|
851
|
-
return
|
|
706
|
+
return node != null && node.tree === this.tree;
|
|
852
707
|
}
|
|
853
708
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
709
|
+
private createFolderElement(node: Node) {
|
|
710
|
+
const closedIconElement = this.renderer.closedIconElement;
|
|
711
|
+
const getScrollLeft = this.scrollHandler.getScrollLeft.bind(
|
|
712
|
+
this.scrollHandler,
|
|
713
|
+
);
|
|
714
|
+
const openedIconElement = this.renderer.openedIconElement;
|
|
715
|
+
const tabIndex = this.options.tabIndex;
|
|
716
|
+
const treeElement = this.element.get(0) as HTMLElement;
|
|
717
|
+
const triggerEvent = this.triggerEvent.bind(this);
|
|
861
718
|
|
|
862
|
-
|
|
719
|
+
return new FolderElement({
|
|
720
|
+
closedIconElement,
|
|
721
|
+
getScrollLeft,
|
|
722
|
+
node,
|
|
723
|
+
openedIconElement,
|
|
724
|
+
tabIndex,
|
|
725
|
+
treeElement,
|
|
726
|
+
triggerEvent,
|
|
727
|
+
});
|
|
728
|
+
}
|
|
863
729
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
730
|
+
private createNodeElement(node: Node) {
|
|
731
|
+
const getScrollLeft = this.scrollHandler.getScrollLeft.bind(
|
|
732
|
+
this.scrollHandler,
|
|
733
|
+
);
|
|
734
|
+
const tabIndex = this.options.tabIndex;
|
|
735
|
+
const treeElement = this.element.get(0) as HTMLElement;
|
|
867
736
|
|
|
868
|
-
return
|
|
737
|
+
return new NodeElement({
|
|
738
|
+
getScrollLeft,
|
|
739
|
+
node,
|
|
740
|
+
tabIndex,
|
|
741
|
+
treeElement,
|
|
742
|
+
});
|
|
869
743
|
}
|
|
870
744
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
745
|
+
private deselectCurrentNode(): void {
|
|
746
|
+
const node = this.getSelectedNode();
|
|
747
|
+
if (node) {
|
|
748
|
+
this.removeFromSelection(node);
|
|
874
749
|
}
|
|
750
|
+
}
|
|
875
751
|
|
|
876
|
-
|
|
877
|
-
|
|
752
|
+
private deselectNodes(parentNode: Node): void {
|
|
753
|
+
const selectedNodesUnderParent =
|
|
754
|
+
this.selectNodeHandler.getSelectedNodesUnder(parentNode);
|
|
755
|
+
for (const n of selectedNodesUnderParent) {
|
|
756
|
+
this.selectNodeHandler.removeFromSelection(n);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
878
759
|
|
|
879
|
-
|
|
760
|
+
private doLoadData(data: NodeData[] | null, parentNode: Node | null): void {
|
|
761
|
+
if (data) {
|
|
762
|
+
if (parentNode) {
|
|
763
|
+
this.deselectNodes(parentNode);
|
|
764
|
+
this.loadSubtree(data, parentNode);
|
|
765
|
+
} else {
|
|
766
|
+
this.initTree(data);
|
|
767
|
+
}
|
|
880
768
|
|
|
881
|
-
|
|
769
|
+
if (this.isDragging()) {
|
|
770
|
+
this.dndHandler.refresh();
|
|
771
|
+
}
|
|
772
|
+
}
|
|
882
773
|
|
|
883
|
-
|
|
774
|
+
this.triggerEvent("tree.load_data", {
|
|
775
|
+
parent_node: parentNode,
|
|
776
|
+
tree_data: data,
|
|
777
|
+
});
|
|
884
778
|
}
|
|
885
779
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
this.
|
|
780
|
+
private doLoadDataFromUrl(
|
|
781
|
+
urlInfoParam: JQuery.AjaxSettings | null | string,
|
|
782
|
+
parentNode: Node | null,
|
|
783
|
+
onFinished: HandleFinishedLoading | null,
|
|
784
|
+
): void {
|
|
785
|
+
const urlInfo = urlInfoParam ?? this.getDataUrlInfo(parentNode);
|
|
892
786
|
|
|
893
|
-
|
|
787
|
+
this.dataLoader.loadFromUrl(urlInfo, parentNode, onFinished);
|
|
894
788
|
}
|
|
895
789
|
|
|
896
|
-
|
|
790
|
+
private doSelectNode(
|
|
791
|
+
node: Node | null,
|
|
792
|
+
optionsParam?: SelectNodeOptions,
|
|
793
|
+
): void {
|
|
794
|
+
const saveState = (): void => {
|
|
795
|
+
if (this.options.saveState) {
|
|
796
|
+
this.saveStateHandler.saveState();
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
|
|
897
800
|
if (!node) {
|
|
898
|
-
|
|
801
|
+
// Called with empty node -> deselect current node
|
|
802
|
+
this.deselectCurrentNode();
|
|
803
|
+
saveState();
|
|
804
|
+
return;
|
|
899
805
|
}
|
|
806
|
+
const defaultOptions = { mustSetFocus: true, mustToggle: true };
|
|
807
|
+
const selectOptions = { ...defaultOptions, ...(optionsParam ?? {}) };
|
|
900
808
|
|
|
901
|
-
const
|
|
809
|
+
const canSelect = (): boolean => {
|
|
810
|
+
if (this.options.onCanSelectNode) {
|
|
811
|
+
return (
|
|
812
|
+
this.options.selectable &&
|
|
813
|
+
this.options.onCanSelectNode(node)
|
|
814
|
+
);
|
|
815
|
+
} else {
|
|
816
|
+
return this.options.selectable;
|
|
817
|
+
}
|
|
818
|
+
};
|
|
902
819
|
|
|
903
|
-
if (
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
this.options.animationSpeed,
|
|
907
|
-
);
|
|
820
|
+
if (!canSelect()) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
908
823
|
|
|
909
|
-
|
|
824
|
+
if (this.selectNodeHandler.isNodeSelected(node)) {
|
|
825
|
+
if (selectOptions.mustToggle) {
|
|
826
|
+
this.deselectCurrentNode();
|
|
827
|
+
this.triggerEvent("tree.select", {
|
|
828
|
+
node: null,
|
|
829
|
+
previous_node: node,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
} else {
|
|
833
|
+
const deselectedNode = this.getSelectedNode() || null;
|
|
834
|
+
this.deselectCurrentNode();
|
|
835
|
+
this.addToSelection(node, selectOptions.mustSetFocus);
|
|
836
|
+
|
|
837
|
+
this.triggerEvent("tree.select", {
|
|
838
|
+
deselected_node: deselectedNode,
|
|
839
|
+
node,
|
|
840
|
+
});
|
|
841
|
+
this.openParents(node);
|
|
910
842
|
}
|
|
911
843
|
|
|
912
|
-
|
|
844
|
+
saveState();
|
|
913
845
|
}
|
|
914
846
|
|
|
915
|
-
|
|
916
|
-
this.
|
|
917
|
-
|
|
847
|
+
private getAutoOpenMaxLevel(): number {
|
|
848
|
+
if (this.options.autoOpen === true) {
|
|
849
|
+
return -1;
|
|
850
|
+
} else if (typeof this.options.autoOpen === "number") {
|
|
851
|
+
return this.options.autoOpen;
|
|
852
|
+
} else if (typeof this.options.autoOpen === "string") {
|
|
853
|
+
return parseInt(this.options.autoOpen, 10);
|
|
854
|
+
} else {
|
|
855
|
+
return 0;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
918
858
|
|
|
919
|
-
|
|
920
|
-
|
|
859
|
+
private getDataUrlInfo(node: Node | null): JQuery.AjaxSettings | null {
|
|
860
|
+
const dataUrl =
|
|
861
|
+
this.options.dataUrl ?? (this.element.data("url") as null | string);
|
|
921
862
|
|
|
922
|
-
|
|
863
|
+
const getUrlFromString = (url: string): JQuery.AjaxSettings => {
|
|
864
|
+
const urlInfo: JQuery.AjaxSettings = { url };
|
|
923
865
|
|
|
924
|
-
|
|
925
|
-
}
|
|
866
|
+
setUrlInfoData(urlInfo);
|
|
926
867
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
868
|
+
return urlInfo;
|
|
869
|
+
};
|
|
930
870
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
871
|
+
const setUrlInfoData = (urlInfo: JQuery.AjaxSettings): void => {
|
|
872
|
+
if (node?.id) {
|
|
873
|
+
// Load on demand of a subtree; add node parameter
|
|
874
|
+
const data = { node: node.id };
|
|
875
|
+
urlInfo.data = data;
|
|
876
|
+
} else {
|
|
877
|
+
// Add selected_node parameter
|
|
878
|
+
const selectedNodeId = this.getNodeIdToBeSelected();
|
|
879
|
+
if (selectedNodeId) {
|
|
880
|
+
const data = { selected_node: selectedNodeId };
|
|
881
|
+
urlInfo.data = data;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
};
|
|
938
885
|
|
|
939
|
-
if (
|
|
886
|
+
if (typeof dataUrl === "function") {
|
|
887
|
+
return dataUrl(node);
|
|
888
|
+
} else if (typeof dataUrl === "string") {
|
|
889
|
+
return getUrlFromString(dataUrl);
|
|
890
|
+
} else if (dataUrl && typeof dataUrl === "object") {
|
|
891
|
+
setUrlInfoData(dataUrl);
|
|
892
|
+
return dataUrl;
|
|
893
|
+
} else {
|
|
940
894
|
return null;
|
|
941
895
|
}
|
|
942
|
-
|
|
943
|
-
return this.getNode(element);
|
|
944
896
|
}
|
|
945
897
|
|
|
946
|
-
|
|
947
|
-
|
|
898
|
+
private getDefaultClosedIcon(): string {
|
|
899
|
+
if (this.options.rtl) {
|
|
900
|
+
// triangle to the left
|
|
901
|
+
return "◀";
|
|
902
|
+
} else {
|
|
903
|
+
// triangle to the right
|
|
904
|
+
return "►";
|
|
905
|
+
}
|
|
948
906
|
}
|
|
949
907
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
}
|
|
908
|
+
private getNode(element: HTMLElement): Node | null {
|
|
909
|
+
const liElement = element.closest("li.jqtree_common");
|
|
953
910
|
|
|
954
|
-
|
|
955
|
-
|
|
911
|
+
if (liElement) {
|
|
912
|
+
return jQuery(liElement).data("node") as Node;
|
|
913
|
+
} else {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
956
916
|
}
|
|
957
917
|
|
|
958
|
-
|
|
959
|
-
|
|
918
|
+
private getNodeElement(element: HTMLElement): NodeElement | null {
|
|
919
|
+
const node = this.getNode(element);
|
|
920
|
+
if (node) {
|
|
921
|
+
return this.getNodeElementForNode(node);
|
|
922
|
+
} else {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
960
925
|
}
|
|
961
926
|
|
|
962
|
-
|
|
963
|
-
|
|
927
|
+
private getNodeElementForNode(node: Node): NodeElement {
|
|
928
|
+
if (node.isFolder()) {
|
|
929
|
+
return this.createFolderElement(node);
|
|
930
|
+
} else {
|
|
931
|
+
return this.createNodeElement(node);
|
|
932
|
+
}
|
|
964
933
|
}
|
|
965
934
|
|
|
966
|
-
|
|
967
|
-
|
|
935
|
+
private getNodeIdToBeSelected(): NodeId | null {
|
|
936
|
+
if (this.options.saveState) {
|
|
937
|
+
return this.saveStateHandler.getNodeIdToBeSelected();
|
|
938
|
+
} else {
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
968
941
|
}
|
|
969
942
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
943
|
+
private getRtlOption(): boolean {
|
|
944
|
+
if (this.options.rtl != null) {
|
|
945
|
+
return this.options.rtl;
|
|
946
|
+
} else {
|
|
947
|
+
const dataRtl = this.element.data("rtl") as unknown;
|
|
973
948
|
|
|
974
|
-
|
|
975
|
-
|
|
949
|
+
if (
|
|
950
|
+
dataRtl !== null &&
|
|
951
|
+
dataRtl !== false &&
|
|
952
|
+
dataRtl !== undefined
|
|
953
|
+
) {
|
|
954
|
+
return true;
|
|
955
|
+
} else {
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
976
959
|
}
|
|
977
960
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
961
|
+
private initData(): void {
|
|
962
|
+
if (this.options.data) {
|
|
963
|
+
this.doLoadData(this.options.data, null);
|
|
964
|
+
} else {
|
|
965
|
+
const dataUrl = this.getDataUrlInfo(null);
|
|
981
966
|
|
|
982
|
-
|
|
983
|
-
|
|
967
|
+
if (dataUrl) {
|
|
968
|
+
this.doLoadDataFromUrl(null, null, null);
|
|
969
|
+
} else {
|
|
970
|
+
this.doLoadData([], null);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
984
973
|
}
|
|
985
974
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
975
|
+
private initTree(data: NodeData[]): void {
|
|
976
|
+
const doInit = (): void => {
|
|
977
|
+
if (!this.isInitialized) {
|
|
978
|
+
this.isInitialized = true;
|
|
979
|
+
this.triggerEvent("tree.init");
|
|
980
|
+
}
|
|
981
|
+
};
|
|
991
982
|
|
|
992
|
-
this.
|
|
983
|
+
this.tree = new this.options.nodeClass(
|
|
984
|
+
null,
|
|
985
|
+
true,
|
|
986
|
+
this.options.nodeClass,
|
|
987
|
+
);
|
|
993
988
|
|
|
994
|
-
|
|
995
|
-
this.options.closedIcon = this.getDefaultClosedIcon();
|
|
996
|
-
}
|
|
989
|
+
this.selectNodeHandler.clear();
|
|
997
990
|
|
|
998
|
-
this.
|
|
991
|
+
this.tree.loadFromData(data);
|
|
999
992
|
|
|
1000
|
-
this.
|
|
1001
|
-
}
|
|
993
|
+
const mustLoadOnDemand = this.setInitialState();
|
|
1002
994
|
|
|
1003
|
-
|
|
1004
|
-
return this.dndHandler.isDragging;
|
|
1005
|
-
}
|
|
995
|
+
this.refreshElements(null);
|
|
1006
996
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
997
|
+
if (!mustLoadOnDemand) {
|
|
998
|
+
doInit();
|
|
999
|
+
} else {
|
|
1000
|
+
// Load data on demand and then init the tree
|
|
1001
|
+
this.setInitialStateOnDemand(doInit);
|
|
1010
1002
|
}
|
|
1011
|
-
|
|
1012
|
-
return this.selectNodeHandler.isNodeSelected(node);
|
|
1013
1003
|
}
|
|
1014
1004
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1005
|
+
private isFocusOnTree(): boolean {
|
|
1006
|
+
const activeElement = document.activeElement;
|
|
1007
|
+
|
|
1008
|
+
return Boolean(
|
|
1009
|
+
activeElement &&
|
|
1010
|
+
activeElement.tagName === "SPAN" &&
|
|
1011
|
+
this.containsElement(activeElement as HTMLElement),
|
|
1012
|
+
);
|
|
1018
1013
|
}
|
|
1019
1014
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
- loadDataFromUrl(url, parent_node=null, on_finished=null)
|
|
1023
|
-
loadDataFromUrl('/my_data');
|
|
1024
|
-
loadDataFromUrl('/my_data', node1);
|
|
1025
|
-
loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
|
|
1026
|
-
loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
|
|
1015
|
+
private isSelectedNodeInSubtree(subtree: Node): boolean {
|
|
1016
|
+
const selectedNode = this.getSelectedNode();
|
|
1027
1017
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
loadDataFromUrl(node1);
|
|
1031
|
-
loadDataFromUrl(null, function() { console.log('finished'); });
|
|
1032
|
-
loadDataFromUrl(node1, function() { console.log('finished'); });
|
|
1033
|
-
*/
|
|
1034
|
-
public loadDataFromUrl(
|
|
1035
|
-
param1: Node | null | string,
|
|
1036
|
-
param2?: HandleFinishedLoading | Node | null,
|
|
1037
|
-
param3?: HandleFinishedLoading,
|
|
1038
|
-
): JQuery {
|
|
1039
|
-
if (typeof param1 === "string") {
|
|
1040
|
-
// first parameter is url
|
|
1041
|
-
this.doLoadDataFromUrl(
|
|
1042
|
-
param1,
|
|
1043
|
-
param2 as Node | null,
|
|
1044
|
-
param3 ?? null,
|
|
1045
|
-
);
|
|
1018
|
+
if (!selectedNode) {
|
|
1019
|
+
return false;
|
|
1046
1020
|
} else {
|
|
1047
|
-
|
|
1048
|
-
this.doLoadDataFromUrl(
|
|
1049
|
-
null,
|
|
1050
|
-
param1,
|
|
1051
|
-
param2 as HandleFinishedLoading | null,
|
|
1052
|
-
);
|
|
1021
|
+
return subtree === selectedNode || subtree.isParentOf(selectedNode);
|
|
1053
1022
|
}
|
|
1054
|
-
|
|
1055
|
-
return this.element;
|
|
1056
1023
|
}
|
|
1057
1024
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1025
|
+
private loadFolderOnDemand(
|
|
1026
|
+
node: Node,
|
|
1027
|
+
slide = true,
|
|
1028
|
+
onFinished?: OnFinishOpenNode,
|
|
1029
|
+
): void {
|
|
1030
|
+
node.is_loading = true;
|
|
1063
1031
|
|
|
1064
|
-
|
|
1032
|
+
this.doLoadDataFromUrl(null, node, () => {
|
|
1033
|
+
this.openNodeInternal(node, slide, onFinished);
|
|
1034
|
+
});
|
|
1065
1035
|
}
|
|
1066
1036
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
throw Error(NODE_PARAM_IS_EMPTY);
|
|
1070
|
-
}
|
|
1037
|
+
private loadSubtree(data: NodeData[], parentNode: Node): void {
|
|
1038
|
+
parentNode.loadFromData(data);
|
|
1071
1039
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1040
|
+
parentNode.load_on_demand = false;
|
|
1041
|
+
parentNode.is_loading = false;
|
|
1075
1042
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1043
|
+
this.refreshElements(parentNode);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
private mouseCapture(positionInfo: PositionInfo): boolean | null {
|
|
1047
|
+
if (this.options.dragAndDrop) {
|
|
1048
|
+
return this.dndHandler.mouseCapture(positionInfo);
|
|
1049
|
+
} else {
|
|
1050
|
+
return false;
|
|
1078
1051
|
}
|
|
1052
|
+
}
|
|
1079
1053
|
|
|
1080
|
-
|
|
1054
|
+
private mouseDrag(positionInfo: PositionInfo): boolean {
|
|
1055
|
+
if (this.options.dragAndDrop) {
|
|
1056
|
+
const result = this.dndHandler.mouseDrag(positionInfo);
|
|
1081
1057
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1058
|
+
this.scrollHandler.checkScrolling(positionInfo);
|
|
1059
|
+
return result;
|
|
1060
|
+
} else {
|
|
1061
|
+
return false;
|
|
1085
1062
|
}
|
|
1086
|
-
|
|
1087
|
-
return this.element;
|
|
1088
1063
|
}
|
|
1089
1064
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1065
|
+
private mouseStart(positionInfo: PositionInfo): boolean {
|
|
1066
|
+
if (this.options.dragAndDrop) {
|
|
1067
|
+
return this.dndHandler.mouseStart(positionInfo);
|
|
1068
|
+
} else {
|
|
1069
|
+
return false;
|
|
1094
1070
|
}
|
|
1095
|
-
|
|
1096
|
-
return this.element;
|
|
1097
1071
|
}
|
|
1098
1072
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
throw Error(NODE_PARAM_IS_EMPTY);
|
|
1073
|
+
private mouseStop(positionInfo: PositionInfo): boolean {
|
|
1074
|
+
if (this.options.dragAndDrop) {
|
|
1075
|
+
this.scrollHandler.stopScrolling();
|
|
1076
|
+
return this.dndHandler.mouseStop(positionInfo);
|
|
1077
|
+
} else {
|
|
1078
|
+
return false;
|
|
1106
1079
|
}
|
|
1107
|
-
|
|
1108
|
-
const parseParams = (): [boolean, OnFinishOpenNode | undefined] => {
|
|
1109
|
-
let onFinished: null | OnFinishOpenNode;
|
|
1110
|
-
let slide: boolean | null;
|
|
1111
|
-
|
|
1112
|
-
if (isFunction(param1)) {
|
|
1113
|
-
onFinished = param1 as OnFinishOpenNode;
|
|
1114
|
-
slide = null;
|
|
1115
|
-
} else {
|
|
1116
|
-
slide = param1 as boolean;
|
|
1117
|
-
onFinished = param2 as OnFinishOpenNode;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
if (slide == null) {
|
|
1121
|
-
slide = this.options.slide;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
return [slide, onFinished];
|
|
1125
|
-
};
|
|
1126
|
-
|
|
1127
|
-
const [slide, onFinished] = parseParams();
|
|
1128
|
-
|
|
1129
|
-
this.openNodeInternal(node, slide, onFinished);
|
|
1130
|
-
return this.element;
|
|
1131
1080
|
}
|
|
1132
1081
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1082
|
+
private openNodeInternal(
|
|
1083
|
+
node: Node,
|
|
1084
|
+
slide = true,
|
|
1085
|
+
onFinished?: OnFinishOpenNode,
|
|
1086
|
+
): void {
|
|
1087
|
+
const doOpenNode = (
|
|
1088
|
+
_node: Node,
|
|
1089
|
+
_slide: boolean,
|
|
1090
|
+
_onFinished?: OnFinishOpenNode,
|
|
1091
|
+
): void => {
|
|
1092
|
+
if (!node.children.length) {
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1135
1095
|
|
|
1136
|
-
|
|
1096
|
+
const folderElement = this.createFolderElement(_node);
|
|
1097
|
+
folderElement.open(
|
|
1098
|
+
_onFinished,
|
|
1099
|
+
_slide,
|
|
1100
|
+
this.options.animationSpeed,
|
|
1101
|
+
);
|
|
1102
|
+
};
|
|
1137
1103
|
|
|
1138
|
-
|
|
1104
|
+
if (node.isFolder() || node.isEmptyFolder) {
|
|
1105
|
+
if (node.load_on_demand) {
|
|
1106
|
+
this.loadFolderOnDemand(node, slide, onFinished);
|
|
1107
|
+
} else {
|
|
1108
|
+
let parent = node.parent;
|
|
1139
1109
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1110
|
+
while (parent) {
|
|
1111
|
+
// nb: do not open root element
|
|
1112
|
+
if (parent.parent) {
|
|
1113
|
+
doOpenNode(parent, false);
|
|
1114
|
+
}
|
|
1115
|
+
parent = parent.parent;
|
|
1116
|
+
}
|
|
1142
1117
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1118
|
+
doOpenNode(node, slide, onFinished);
|
|
1119
|
+
this.saveState();
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1146
1122
|
}
|
|
1147
1123
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
return this.element;
|
|
1151
|
-
}
|
|
1124
|
+
private openParents(node: Node) {
|
|
1125
|
+
const parent = node.parent;
|
|
1152
1126
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1127
|
+
if (parent?.parent && !parent.is_open) {
|
|
1128
|
+
this.openNode(parent, false);
|
|
1129
|
+
}
|
|
1156
1130
|
}
|
|
1157
1131
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1132
|
+
/*
|
|
1133
|
+
Redraw the tree or part of the tree.
|
|
1134
|
+
from_node: redraw this subtree
|
|
1135
|
+
*/
|
|
1136
|
+
private refreshElements(fromNode: Node | null): void {
|
|
1137
|
+
const mustSetFocus = this.isFocusOnTree();
|
|
1138
|
+
const mustSelect = fromNode
|
|
1139
|
+
? this.isSelectedNodeInSubtree(fromNode)
|
|
1140
|
+
: false;
|
|
1162
1141
|
|
|
1163
|
-
this.
|
|
1142
|
+
this.renderer.render(fromNode);
|
|
1164
1143
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1144
|
+
if (mustSelect) {
|
|
1145
|
+
this.selectCurrentNode(mustSetFocus);
|
|
1146
|
+
}
|
|
1167
1147
|
|
|
1168
|
-
|
|
1148
|
+
this.triggerEvent("tree.refresh");
|
|
1169
1149
|
}
|
|
1170
1150
|
|
|
1171
|
-
|
|
1172
|
-
if (
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
if (!node.parent) {
|
|
1177
|
-
throw Error("Node has no parent");
|
|
1151
|
+
private saveState(): void {
|
|
1152
|
+
if (this.options.saveState) {
|
|
1153
|
+
this.saveStateHandler.saveState();
|
|
1178
1154
|
}
|
|
1179
|
-
|
|
1180
|
-
this.selectNodeHandler.removeFromSelection(node, true); // including children
|
|
1181
|
-
|
|
1182
|
-
const parent = node.parent;
|
|
1183
|
-
node.remove();
|
|
1184
|
-
this.refreshElements(parent);
|
|
1185
|
-
|
|
1186
|
-
return this.element;
|
|
1187
1155
|
}
|
|
1188
1156
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1157
|
+
private selectCurrentNode(mustSetFocus: boolean): void {
|
|
1158
|
+
const node = this.getSelectedNode();
|
|
1159
|
+
if (node) {
|
|
1160
|
+
const nodeElement = this.getNodeElementForNode(node);
|
|
1161
|
+
nodeElement.select(mustSetFocus);
|
|
1192
1162
|
}
|
|
1163
|
+
}
|
|
1193
1164
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1165
|
+
// Set initial state, either by restoring the state or auto-opening nodes
|
|
1166
|
+
// result: must load nodes on demand?
|
|
1167
|
+
private setInitialState(): boolean {
|
|
1168
|
+
const restoreState = (): [boolean, boolean] => {
|
|
1169
|
+
// result: is state restored, must load on demand?
|
|
1170
|
+
if (!this.options.saveState) {
|
|
1171
|
+
return [false, false];
|
|
1172
|
+
} else {
|
|
1173
|
+
const state = this.saveStateHandler.getStateFromStorage();
|
|
1197
1174
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1175
|
+
if (!state) {
|
|
1176
|
+
return [false, false];
|
|
1177
|
+
} else {
|
|
1178
|
+
const mustLoadOnDemand =
|
|
1179
|
+
this.saveStateHandler.setInitialState(state);
|
|
1201
1180
|
|
|
1202
|
-
|
|
1181
|
+
// return true: the state is restored
|
|
1182
|
+
return [true, mustLoadOnDemand];
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1203
1186
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1187
|
+
const autoOpenNodes = (): boolean => {
|
|
1188
|
+
// result: must load on demand?
|
|
1189
|
+
if (this.options.autoOpen === false) {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1206
1192
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
optionsParam?: SelectNodeOptions,
|
|
1210
|
-
): JQuery {
|
|
1211
|
-
this.doSelectNode(node, optionsParam);
|
|
1212
|
-
return this.element;
|
|
1213
|
-
}
|
|
1193
|
+
const maxLevel = this.getAutoOpenMaxLevel();
|
|
1194
|
+
let mustLoadOnDemand = false;
|
|
1214
1195
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1196
|
+
this.tree.iterate((node: Node, level: number) => {
|
|
1197
|
+
if (node.load_on_demand) {
|
|
1198
|
+
mustLoadOnDemand = true;
|
|
1199
|
+
return false;
|
|
1200
|
+
} else if (!node.hasChildren()) {
|
|
1201
|
+
return false;
|
|
1202
|
+
} else {
|
|
1203
|
+
node.is_open = true;
|
|
1204
|
+
return level !== maxLevel;
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1219
1207
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
this.saveStateHandler.setInitialState(state);
|
|
1223
|
-
this.refreshElements(null);
|
|
1224
|
-
}
|
|
1208
|
+
return mustLoadOnDemand;
|
|
1209
|
+
};
|
|
1225
1210
|
|
|
1226
|
-
|
|
1227
|
-
}
|
|
1211
|
+
let [isRestored, mustLoadOnDemand] = restoreState(); // eslint-disable-line prefer-const
|
|
1228
1212
|
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
throw Error(NODE_PARAM_IS_EMPTY);
|
|
1213
|
+
if (!isRestored) {
|
|
1214
|
+
mustLoadOnDemand = autoOpenNodes();
|
|
1232
1215
|
}
|
|
1233
1216
|
|
|
1234
|
-
|
|
1217
|
+
return mustLoadOnDemand;
|
|
1218
|
+
}
|
|
1235
1219
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1220
|
+
// Set the initial state for nodes that are loaded on demand
|
|
1221
|
+
// Call cb_finished when done
|
|
1222
|
+
private setInitialStateOnDemand(cbFinished: () => void): void {
|
|
1223
|
+
const restoreState = (): boolean => {
|
|
1224
|
+
if (!this.options.saveState) {
|
|
1225
|
+
return false;
|
|
1226
|
+
} else {
|
|
1227
|
+
const state = this.saveStateHandler.getStateFromStorage();
|
|
1241
1228
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1229
|
+
if (!state) {
|
|
1230
|
+
return false;
|
|
1231
|
+
} else {
|
|
1232
|
+
this.saveStateHandler.setInitialStateOnDemand(
|
|
1233
|
+
state,
|
|
1234
|
+
cbFinished,
|
|
1235
|
+
);
|
|
1244
1236
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1237
|
+
return true;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1248
1241
|
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
}
|
|
1242
|
+
const autoOpenNodes = (): void => {
|
|
1243
|
+
const maxLevel = this.getAutoOpenMaxLevel();
|
|
1244
|
+
let loadingCount = 0;
|
|
1253
1245
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1246
|
+
const loadAndOpenNode = (node: Node): void => {
|
|
1247
|
+
loadingCount += 1;
|
|
1248
|
+
this.openNodeInternal(node, false, () => {
|
|
1249
|
+
loadingCount -= 1;
|
|
1250
|
+
openNodes();
|
|
1251
|
+
});
|
|
1252
|
+
};
|
|
1257
1253
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1254
|
+
const openNodes = (): void => {
|
|
1255
|
+
this.tree.iterate((node: Node, level: number) => {
|
|
1256
|
+
if (node.load_on_demand) {
|
|
1257
|
+
if (!node.is_loading) {
|
|
1258
|
+
loadAndOpenNode(node);
|
|
1259
|
+
}
|
|
1260
1260
|
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1261
|
+
return false;
|
|
1262
|
+
} else {
|
|
1263
|
+
this.openNodeInternal(node, false);
|
|
1264
1264
|
|
|
1265
|
-
|
|
1265
|
+
return level !== maxLevel;
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1266
1268
|
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1269
|
+
if (loadingCount === 0) {
|
|
1270
|
+
cbFinished();
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1270
1273
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
data.children &&
|
|
1274
|
-
data.children instanceof Array
|
|
1275
|
-
) {
|
|
1276
|
-
node.removeChildren();
|
|
1274
|
+
openNodes();
|
|
1275
|
+
};
|
|
1277
1276
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}
|
|
1277
|
+
if (!restoreState()) {
|
|
1278
|
+
autoOpenNodes();
|
|
1281
1279
|
}
|
|
1280
|
+
}
|
|
1282
1281
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1282
|
+
private triggerEvent(
|
|
1283
|
+
eventName: string,
|
|
1284
|
+
values?: Record<string, unknown>,
|
|
1285
|
+
): JQuery.Event {
|
|
1286
|
+
const event = jQuery.Event(eventName, values);
|
|
1287
|
+
this.element.trigger(event);
|
|
1288
|
+
return event;
|
|
1286
1289
|
}
|
|
1287
1290
|
}
|
|
1288
1291
|
|