jqtree 1.8.8 → 1.8.10
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 +20 -18
- 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 +43 -43
- package/src/mouseHandler.ts +152 -152
- package/src/node.ts +32 -34
- package/src/nodeElement/folderElement.ts +11 -11
- package/src/nodeElement/ghostDropHint.ts +8 -9
- package/src/nodeElement/index.ts +18 -19
- package/src/saveStateHandler.ts +70 -70
- package/src/scrollHandler/containerScrollParent.ts +58 -58
- package/src/scrollHandler/documentScrollParent.ts +60 -60
- package/src/scrollHandler.ts +17 -17
- package/src/tree.jquery.d.ts +37 -37
- package/src/tree.jquery.ts +936 -937
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +1348 -1364
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +3 -3
- 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,1215 +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.get(0) as HTMLElement;
|
|
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
|
-
closedIconElement,
|
|
258
|
-
getScrollLeft,
|
|
259
|
-
node,
|
|
260
|
-
openedIconElement,
|
|
261
|
-
tabIndex,
|
|
262
|
-
treeElement,
|
|
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.get(0) as HTMLElement;
|
|
147
|
+
this.refreshElements(parentNode);
|
|
273
148
|
|
|
274
|
-
return
|
|
275
|
-
getScrollLeft,
|
|
276
|
-
node,
|
|
277
|
-
tabIndex,
|
|
278
|
-
treeElement,
|
|
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
|
-
|
|
498
|
-
private initData(): void {
|
|
499
|
-
if (this.options.data) {
|
|
500
|
-
this.doLoadData(this.options.data, null);
|
|
501
|
-
} else {
|
|
502
|
-
const dataUrl = this.getDataUrlInfo(null);
|
|
503
331
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
} else {
|
|
507
|
-
this.doLoadData([], null);
|
|
508
|
-
}
|
|
332
|
+
if (!targetNode) {
|
|
333
|
+
throw Error(PARAM_IS_EMPTY + "targetNode");
|
|
509
334
|
}
|
|
510
|
-
}
|
|
511
335
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
this.isInitialized = true;
|
|
516
|
-
this.triggerEvent("tree.init");
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
this.tree = new this.options.nodeClass(
|
|
521
|
-
null,
|
|
522
|
-
true,
|
|
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
|
-
|
|
399
|
+
public refresh(): JQuery {
|
|
400
|
+
this.refreshElements(null);
|
|
401
|
+
return this.element;
|
|
402
|
+
}
|
|
594
403
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
404
|
+
public refreshHitAreas(): JQuery {
|
|
405
|
+
this.dndHandler.refresh();
|
|
406
|
+
return this.element;
|
|
600
407
|
}
|
|
601
408
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
} else {
|
|
606
|
-
return false;
|
|
607
|
-
}
|
|
409
|
+
public reload(onFinished: HandleFinishedLoading | null): JQuery {
|
|
410
|
+
this.doLoadDataFromUrl(null, null, onFinished);
|
|
411
|
+
return this.element;
|
|
608
412
|
}
|
|
609
413
|
|
|
610
|
-
|
|
611
|
-
if (
|
|
612
|
-
|
|
613
|
-
return this.dndHandler.mouseStop(positionInfo);
|
|
614
|
-
} else {
|
|
615
|
-
return false;
|
|
414
|
+
public removeFromSelection(node?: Node): JQuery {
|
|
415
|
+
if (!node) {
|
|
416
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
616
417
|
}
|
|
617
|
-
}
|
|
618
418
|
|
|
619
|
-
|
|
620
|
-
node: Node,
|
|
621
|
-
slide = true,
|
|
622
|
-
onFinished?: OnFinishOpenNode,
|
|
623
|
-
): void {
|
|
624
|
-
const doOpenNode = (
|
|
625
|
-
_node: Node,
|
|
626
|
-
_slide: boolean,
|
|
627
|
-
_onFinished?: OnFinishOpenNode,
|
|
628
|
-
): void => {
|
|
629
|
-
if (!node.children.length) {
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
419
|
+
this.selectNodeHandler.removeFromSelection(node);
|
|
632
420
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
_onFinished,
|
|
636
|
-
_slide,
|
|
637
|
-
this.options.animationSpeed,
|
|
638
|
-
);
|
|
639
|
-
};
|
|
421
|
+
this.getNodeElementForNode(node).deselect();
|
|
422
|
+
this.saveState();
|
|
640
423
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
this.loadFolderOnDemand(node, slide, onFinished);
|
|
644
|
-
} else {
|
|
645
|
-
let parent = node.parent;
|
|
424
|
+
return this.element;
|
|
425
|
+
}
|
|
646
426
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
parent = parent.parent;
|
|
653
|
-
}
|
|
427
|
+
public removeNode(node?: Node): JQuery {
|
|
428
|
+
if (!node) {
|
|
429
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
430
|
+
}
|
|
654
431
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
}
|
|
432
|
+
if (!node.parent) {
|
|
433
|
+
throw Error("Node has no parent");
|
|
658
434
|
}
|
|
659
|
-
}
|
|
660
435
|
|
|
661
|
-
|
|
436
|
+
this.selectNodeHandler.removeFromSelection(node, true); // including children
|
|
437
|
+
|
|
662
438
|
const parent = node.parent;
|
|
439
|
+
node.remove();
|
|
440
|
+
this.refreshElements(parent);
|
|
663
441
|
|
|
664
|
-
|
|
665
|
-
this.openNode(parent, false);
|
|
666
|
-
}
|
|
442
|
+
return this.element;
|
|
667
443
|
}
|
|
668
444
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
private refreshElements(fromNode: Node | null): void {
|
|
674
|
-
const mustSetFocus = this.isFocusOnTree();
|
|
675
|
-
const mustSelect = fromNode
|
|
676
|
-
? this.isSelectedNodeInSubtree(fromNode)
|
|
677
|
-
: false;
|
|
678
|
-
|
|
679
|
-
this.renderer.render(fromNode);
|
|
445
|
+
public scrollToNode(node?: Node): JQuery {
|
|
446
|
+
if (!node) {
|
|
447
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
448
|
+
}
|
|
680
449
|
|
|
681
|
-
if (
|
|
682
|
-
this.
|
|
450
|
+
if (!node.element) {
|
|
451
|
+
return this.element;
|
|
683
452
|
}
|
|
684
453
|
|
|
685
|
-
|
|
686
|
-
|
|
454
|
+
const top =
|
|
455
|
+
getOffsetTop(node.element) -
|
|
456
|
+
getOffsetTop(this.$el.get(0) as HTMLElement);
|
|
687
457
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
458
|
+
this.scrollHandler.scrollToY(top);
|
|
459
|
+
|
|
460
|
+
return this.element;
|
|
692
461
|
}
|
|
693
462
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
463
|
+
public selectNode(
|
|
464
|
+
node: Node | null,
|
|
465
|
+
optionsParam?: SelectNodeOptions,
|
|
466
|
+
): JQuery {
|
|
467
|
+
this.doSelectNode(node, optionsParam);
|
|
468
|
+
return this.element;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
public setOption(option: string, value: unknown): JQuery {
|
|
472
|
+
(this.options as unknown as Record<string, unknown>)[option] = value;
|
|
473
|
+
return this.element;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
public setState(state?: SavedState): JQuery {
|
|
477
|
+
if (state) {
|
|
478
|
+
this.saveStateHandler.setInitialState(state);
|
|
479
|
+
this.refreshElements(null);
|
|
699
480
|
}
|
|
481
|
+
|
|
482
|
+
return this.element;
|
|
700
483
|
}
|
|
701
484
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
// result: is state restored, must load on demand?
|
|
707
|
-
if (!this.options.saveState) {
|
|
708
|
-
return [false, false];
|
|
709
|
-
} else {
|
|
710
|
-
const state = this.saveStateHandler.getStateFromStorage();
|
|
485
|
+
public toggle(node?: Node, slideParam: boolean | null = null): JQuery {
|
|
486
|
+
if (!node) {
|
|
487
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
488
|
+
}
|
|
711
489
|
|
|
712
|
-
|
|
713
|
-
return [false, false];
|
|
714
|
-
} else {
|
|
715
|
-
const mustLoadOnDemand =
|
|
716
|
-
this.saveStateHandler.setInitialState(state);
|
|
490
|
+
const slide = slideParam ?? this.options.slide;
|
|
717
491
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
}
|
|
492
|
+
if (node.is_open) {
|
|
493
|
+
this.closeNode(node, slide);
|
|
494
|
+
} else {
|
|
495
|
+
this.openNode(node, slide);
|
|
496
|
+
}
|
|
723
497
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (this.options.autoOpen === false) {
|
|
727
|
-
return false;
|
|
728
|
-
}
|
|
498
|
+
return this.element;
|
|
499
|
+
}
|
|
729
500
|
|
|
730
|
-
|
|
731
|
-
|
|
501
|
+
public toJson(): string {
|
|
502
|
+
return JSON.stringify(this.tree.getData());
|
|
503
|
+
}
|
|
732
504
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
} else if (!node.hasChildren()) {
|
|
738
|
-
return false;
|
|
739
|
-
} else {
|
|
740
|
-
node.is_open = true;
|
|
741
|
-
return level !== maxLevel;
|
|
742
|
-
}
|
|
743
|
-
});
|
|
505
|
+
public updateNode(node?: Node, data?: NodeData): JQuery {
|
|
506
|
+
if (!node) {
|
|
507
|
+
throw Error(NODE_PARAM_IS_EMPTY);
|
|
508
|
+
}
|
|
744
509
|
|
|
745
|
-
|
|
746
|
-
|
|
510
|
+
if (!data) {
|
|
511
|
+
return this.element;
|
|
512
|
+
}
|
|
747
513
|
|
|
748
|
-
|
|
514
|
+
const idIsChanged =
|
|
515
|
+
typeof data === "object" && data.id && data.id !== node.id;
|
|
749
516
|
|
|
750
|
-
if (
|
|
751
|
-
|
|
517
|
+
if (idIsChanged) {
|
|
518
|
+
this.tree.removeNodeFromIndex(node);
|
|
752
519
|
}
|
|
753
520
|
|
|
754
|
-
|
|
755
|
-
}
|
|
521
|
+
node.setData(data);
|
|
756
522
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
const restoreState = (): boolean => {
|
|
761
|
-
if (!this.options.saveState) {
|
|
762
|
-
return false;
|
|
763
|
-
} else {
|
|
764
|
-
const state = this.saveStateHandler.getStateFromStorage();
|
|
523
|
+
if (idIsChanged) {
|
|
524
|
+
this.tree.addNodeToIndex(node);
|
|
525
|
+
}
|
|
765
526
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
);
|
|
527
|
+
if (
|
|
528
|
+
typeof data === "object" &&
|
|
529
|
+
data.children &&
|
|
530
|
+
data.children instanceof Array
|
|
531
|
+
) {
|
|
532
|
+
node.removeChildren();
|
|
773
533
|
|
|
774
|
-
|
|
775
|
-
|
|
534
|
+
if (data.children.length) {
|
|
535
|
+
node.loadFromData(data.children as Node[]);
|
|
776
536
|
}
|
|
777
|
-
}
|
|
537
|
+
}
|
|
778
538
|
|
|
779
|
-
|
|
780
|
-
const maxLevel = this.getAutoOpenMaxLevel();
|
|
781
|
-
let loadingCount = 0;
|
|
539
|
+
this.refreshElements(node);
|
|
782
540
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
this.openNodeInternal(node, false, () => {
|
|
786
|
-
loadingCount -= 1;
|
|
787
|
-
openNodes();
|
|
788
|
-
});
|
|
789
|
-
};
|
|
541
|
+
return this.element;
|
|
542
|
+
}
|
|
790
543
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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;
|
|
797
570
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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);
|
|
801
586
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
587
|
+
const selectNodeHandler = new SelectNodeHandler({
|
|
588
|
+
getNodeById,
|
|
589
|
+
});
|
|
805
590
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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;
|
|
810
600
|
|
|
811
|
-
|
|
812
|
-
|
|
601
|
+
const dataLoader = new DataLoader({
|
|
602
|
+
dataFilter,
|
|
603
|
+
loadData,
|
|
604
|
+
onLoadFailed,
|
|
605
|
+
onLoading,
|
|
606
|
+
treeElement,
|
|
607
|
+
triggerEvent,
|
|
608
|
+
});
|
|
813
609
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
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
|
+
});
|
|
818
622
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
const event = jQuery.Event(eventName, values);
|
|
824
|
-
this.element.trigger(event);
|
|
825
|
-
return event;
|
|
826
|
-
}
|
|
623
|
+
const scrollHandler = new ScrollHandler({
|
|
624
|
+
refreshHitAreas,
|
|
625
|
+
treeElement,
|
|
626
|
+
});
|
|
827
627
|
|
|
828
|
-
|
|
829
|
-
newNodeInfo: NodeData,
|
|
830
|
-
existingNode: Node,
|
|
831
|
-
): Node | null {
|
|
832
|
-
const newNode = existingNode.addAfter(newNodeInfo);
|
|
628
|
+
const getScrollLeft = scrollHandler.getScrollLeft.bind(scrollHandler);
|
|
833
629
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
+
});
|
|
837
648
|
|
|
838
|
-
|
|
839
|
-
|
|
649
|
+
const keyHandler = new KeyHandler({
|
|
650
|
+
closeNode,
|
|
651
|
+
getSelectedNode,
|
|
652
|
+
isFocusOnTree,
|
|
653
|
+
keyboardSupport,
|
|
654
|
+
openNode,
|
|
655
|
+
selectNode,
|
|
656
|
+
});
|
|
840
657
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
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
|
+
});
|
|
848
672
|
|
|
849
|
-
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
|
+
}
|
|
850
702
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
}
|
|
703
|
+
private containsElement(element: HTMLElement): boolean {
|
|
704
|
+
const node = this.getNode(element);
|
|
854
705
|
|
|
855
|
-
return
|
|
706
|
+
return node != null && node.tree === this.tree;
|
|
856
707
|
}
|
|
857
708
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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);
|
|
865
718
|
|
|
866
|
-
|
|
719
|
+
return new FolderElement({
|
|
720
|
+
closedIconElement,
|
|
721
|
+
getScrollLeft,
|
|
722
|
+
node,
|
|
723
|
+
openedIconElement,
|
|
724
|
+
tabIndex,
|
|
725
|
+
treeElement,
|
|
726
|
+
triggerEvent,
|
|
727
|
+
});
|
|
728
|
+
}
|
|
867
729
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
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;
|
|
871
736
|
|
|
872
|
-
return
|
|
737
|
+
return new NodeElement({
|
|
738
|
+
getScrollLeft,
|
|
739
|
+
node,
|
|
740
|
+
tabIndex,
|
|
741
|
+
treeElement,
|
|
742
|
+
});
|
|
873
743
|
}
|
|
874
744
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
745
|
+
private deselectCurrentNode(): void {
|
|
746
|
+
const node = this.getSelectedNode();
|
|
747
|
+
if (node) {
|
|
748
|
+
this.removeFromSelection(node);
|
|
878
749
|
}
|
|
750
|
+
}
|
|
879
751
|
|
|
880
|
-
|
|
881
|
-
|
|
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
|
+
}
|
|
882
759
|
|
|
883
|
-
|
|
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
|
+
}
|
|
884
768
|
|
|
885
|
-
|
|
769
|
+
if (this.isDragging()) {
|
|
770
|
+
this.dndHandler.refresh();
|
|
771
|
+
}
|
|
772
|
+
}
|
|
886
773
|
|
|
887
|
-
|
|
774
|
+
this.triggerEvent("tree.load_data", {
|
|
775
|
+
parent_node: parentNode,
|
|
776
|
+
tree_data: data,
|
|
777
|
+
});
|
|
888
778
|
}
|
|
889
779
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
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);
|
|
896
786
|
|
|
897
|
-
|
|
787
|
+
this.dataLoader.loadFromUrl(urlInfo, parentNode, onFinished);
|
|
898
788
|
}
|
|
899
789
|
|
|
900
|
-
|
|
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
|
+
|
|
901
800
|
if (!node) {
|
|
902
|
-
|
|
801
|
+
// Called with empty node -> deselect current node
|
|
802
|
+
this.deselectCurrentNode();
|
|
803
|
+
saveState();
|
|
804
|
+
return;
|
|
903
805
|
}
|
|
806
|
+
const defaultOptions = { mustSetFocus: true, mustToggle: true };
|
|
807
|
+
const selectOptions = { ...defaultOptions, ...(optionsParam ?? {}) };
|
|
904
808
|
|
|
905
|
-
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
|
+
};
|
|
906
819
|
|
|
907
|
-
if (
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
this.options.animationSpeed,
|
|
911
|
-
);
|
|
820
|
+
if (!canSelect()) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
912
823
|
|
|
913
|
-
|
|
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);
|
|
914
842
|
}
|
|
915
843
|
|
|
916
|
-
|
|
844
|
+
saveState();
|
|
917
845
|
}
|
|
918
846
|
|
|
919
|
-
|
|
920
|
-
this.
|
|
921
|
-
|
|
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
|
+
}
|
|
922
858
|
|
|
923
|
-
|
|
924
|
-
|
|
859
|
+
private getDataUrlInfo(node: Node | null): JQuery.AjaxSettings | null {
|
|
860
|
+
const dataUrl =
|
|
861
|
+
this.options.dataUrl ?? (this.element.data("url") as null | string);
|
|
925
862
|
|
|
926
|
-
|
|
863
|
+
const getUrlFromString = (url: string): JQuery.AjaxSettings => {
|
|
864
|
+
const urlInfo: JQuery.AjaxSettings = { url };
|
|
927
865
|
|
|
928
|
-
|
|
929
|
-
}
|
|
866
|
+
setUrlInfoData(urlInfo);
|
|
930
867
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
}
|
|
868
|
+
return urlInfo;
|
|
869
|
+
};
|
|
934
870
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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
|
+
};
|
|
942
885
|
|
|
943
|
-
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 {
|
|
944
894
|
return null;
|
|
945
895
|
}
|
|
946
|
-
|
|
947
|
-
return this.getNode(element);
|
|
948
896
|
}
|
|
949
897
|
|
|
950
|
-
|
|
951
|
-
|
|
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
|
+
}
|
|
952
906
|
}
|
|
953
907
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
908
|
+
private getNode(element: HTMLElement): Node | null {
|
|
909
|
+
const liElement = element.closest("li.jqtree_common");
|
|
957
910
|
|
|
958
|
-
|
|
959
|
-
|
|
911
|
+
if (liElement) {
|
|
912
|
+
return jQuery(liElement).data("node") as Node;
|
|
913
|
+
} else {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
960
916
|
}
|
|
961
917
|
|
|
962
|
-
|
|
963
|
-
|
|
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
|
+
}
|
|
964
925
|
}
|
|
965
926
|
|
|
966
|
-
|
|
967
|
-
|
|
927
|
+
private getNodeElementForNode(node: Node): NodeElement {
|
|
928
|
+
if (node.isFolder()) {
|
|
929
|
+
return this.createFolderElement(node);
|
|
930
|
+
} else {
|
|
931
|
+
return this.createNodeElement(node);
|
|
932
|
+
}
|
|
968
933
|
}
|
|
969
934
|
|
|
970
|
-
|
|
971
|
-
|
|
935
|
+
private getNodeIdToBeSelected(): NodeId | null {
|
|
936
|
+
if (this.options.saveState) {
|
|
937
|
+
return this.saveStateHandler.getNodeIdToBeSelected();
|
|
938
|
+
} else {
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
972
941
|
}
|
|
973
942
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
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;
|
|
977
948
|
|
|
978
|
-
|
|
979
|
-
|
|
949
|
+
if (
|
|
950
|
+
dataRtl !== null &&
|
|
951
|
+
dataRtl !== false &&
|
|
952
|
+
dataRtl !== undefined
|
|
953
|
+
) {
|
|
954
|
+
return true;
|
|
955
|
+
} else {
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
980
959
|
}
|
|
981
960
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
961
|
+
private initData(): void {
|
|
962
|
+
if (this.options.data) {
|
|
963
|
+
this.doLoadData(this.options.data, null);
|
|
964
|
+
} else {
|
|
965
|
+
const dataUrl = this.getDataUrlInfo(null);
|
|
985
966
|
|
|
986
|
-
|
|
987
|
-
|
|
967
|
+
if (dataUrl) {
|
|
968
|
+
this.doLoadDataFromUrl(null, null, null);
|
|
969
|
+
} else {
|
|
970
|
+
this.doLoadData([], null);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
988
973
|
}
|
|
989
974
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
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
|
+
};
|
|
995
982
|
|
|
996
|
-
this.
|
|
983
|
+
this.tree = new this.options.nodeClass(
|
|
984
|
+
null,
|
|
985
|
+
true,
|
|
986
|
+
this.options.nodeClass,
|
|
987
|
+
);
|
|
997
988
|
|
|
998
|
-
|
|
999
|
-
this.options.closedIcon = this.getDefaultClosedIcon();
|
|
1000
|
-
}
|
|
989
|
+
this.selectNodeHandler.clear();
|
|
1001
990
|
|
|
1002
|
-
this.
|
|
991
|
+
this.tree.loadFromData(data);
|
|
1003
992
|
|
|
1004
|
-
this.
|
|
1005
|
-
}
|
|
993
|
+
const mustLoadOnDemand = this.setInitialState();
|
|
1006
994
|
|
|
1007
|
-
|
|
1008
|
-
return this.dndHandler.isDragging;
|
|
1009
|
-
}
|
|
995
|
+
this.refreshElements(null);
|
|
1010
996
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
997
|
+
if (!mustLoadOnDemand) {
|
|
998
|
+
doInit();
|
|
999
|
+
} else {
|
|
1000
|
+
// Load data on demand and then init the tree
|
|
1001
|
+
this.setInitialStateOnDemand(doInit);
|
|
1014
1002
|
}
|
|
1015
|
-
|
|
1016
|
-
return this.selectNodeHandler.isNodeSelected(node);
|
|
1017
1003
|
}
|
|
1018
1004
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
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
|
+
);
|
|
1022
1013
|
}
|
|
1023
1014
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
- loadDataFromUrl(url, parent_node=null, on_finished=null)
|
|
1027
|
-
loadDataFromUrl('/my_data');
|
|
1028
|
-
loadDataFromUrl('/my_data', node1);
|
|
1029
|
-
loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
|
|
1030
|
-
loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
|
|
1015
|
+
private isSelectedNodeInSubtree(subtree: Node): boolean {
|
|
1016
|
+
const selectedNode = this.getSelectedNode();
|
|
1031
1017
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
loadDataFromUrl(node1);
|
|
1035
|
-
loadDataFromUrl(null, function() { console.log('finished'); });
|
|
1036
|
-
loadDataFromUrl(node1, function() { console.log('finished'); });
|
|
1037
|
-
*/
|
|
1038
|
-
public loadDataFromUrl(
|
|
1039
|
-
param1: Node | null | string,
|
|
1040
|
-
param2?: HandleFinishedLoading | Node | null,
|
|
1041
|
-
param3?: HandleFinishedLoading,
|
|
1042
|
-
): JQuery {
|
|
1043
|
-
if (typeof param1 === "string") {
|
|
1044
|
-
// first parameter is url
|
|
1045
|
-
this.doLoadDataFromUrl(
|
|
1046
|
-
param1,
|
|
1047
|
-
param2 as Node | null,
|
|
1048
|
-
param3 ?? null,
|
|
1049
|
-
);
|
|
1018
|
+
if (!selectedNode) {
|
|
1019
|
+
return false;
|
|
1050
1020
|
} else {
|
|
1051
|
-
|
|
1052
|
-
this.doLoadDataFromUrl(
|
|
1053
|
-
null,
|
|
1054
|
-
param1,
|
|
1055
|
-
param2 as HandleFinishedLoading | null,
|
|
1056
|
-
);
|
|
1021
|
+
return subtree === selectedNode || subtree.isParentOf(selectedNode);
|
|
1057
1022
|
}
|
|
1058
|
-
|
|
1059
|
-
return this.element;
|
|
1060
1023
|
}
|
|
1061
1024
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1025
|
+
private loadFolderOnDemand(
|
|
1026
|
+
node: Node,
|
|
1027
|
+
slide = true,
|
|
1028
|
+
onFinished?: OnFinishOpenNode,
|
|
1029
|
+
): void {
|
|
1030
|
+
node.is_loading = true;
|
|
1067
1031
|
|
|
1068
|
-
|
|
1032
|
+
this.doLoadDataFromUrl(null, node, () => {
|
|
1033
|
+
this.openNodeInternal(node, slide, onFinished);
|
|
1034
|
+
});
|
|
1069
1035
|
}
|
|
1070
1036
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
throw Error(NODE_PARAM_IS_EMPTY);
|
|
1074
|
-
}
|
|
1037
|
+
private loadSubtree(data: NodeData[], parentNode: Node): void {
|
|
1038
|
+
parentNode.loadFromData(data);
|
|
1075
1039
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1040
|
+
parentNode.load_on_demand = false;
|
|
1041
|
+
parentNode.is_loading = false;
|
|
1079
1042
|
|
|
1080
|
-
|
|
1081
|
-
|
|
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;
|
|
1082
1051
|
}
|
|
1052
|
+
}
|
|
1083
1053
|
|
|
1084
|
-
|
|
1054
|
+
private mouseDrag(positionInfo: PositionInfo): boolean {
|
|
1055
|
+
if (this.options.dragAndDrop) {
|
|
1056
|
+
const result = this.dndHandler.mouseDrag(positionInfo);
|
|
1085
1057
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1058
|
+
this.scrollHandler.checkScrolling(positionInfo);
|
|
1059
|
+
return result;
|
|
1060
|
+
} else {
|
|
1061
|
+
return false;
|
|
1089
1062
|
}
|
|
1090
|
-
|
|
1091
|
-
return this.element;
|
|
1092
1063
|
}
|
|
1093
1064
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1065
|
+
private mouseStart(positionInfo: PositionInfo): boolean {
|
|
1066
|
+
if (this.options.dragAndDrop) {
|
|
1067
|
+
return this.dndHandler.mouseStart(positionInfo);
|
|
1068
|
+
} else {
|
|
1069
|
+
return false;
|
|
1098
1070
|
}
|
|
1099
|
-
|
|
1100
|
-
return this.element;
|
|
1101
1071
|
}
|
|
1102
1072
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
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;
|
|
1110
1079
|
}
|
|
1111
|
-
|
|
1112
|
-
const parseParams = (): [boolean, OnFinishOpenNode | undefined] => {
|
|
1113
|
-
let onFinished: null | OnFinishOpenNode;
|
|
1114
|
-
let slide: boolean | null;
|
|
1115
|
-
|
|
1116
|
-
if (isFunction(param1)) {
|
|
1117
|
-
onFinished = param1 as OnFinishOpenNode;
|
|
1118
|
-
slide = null;
|
|
1119
|
-
} else {
|
|
1120
|
-
slide = param1 as boolean;
|
|
1121
|
-
onFinished = param2 as OnFinishOpenNode;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
if (slide == null) {
|
|
1125
|
-
slide = this.options.slide;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
return [slide, onFinished];
|
|
1129
|
-
};
|
|
1130
|
-
|
|
1131
|
-
const [slide, onFinished] = parseParams();
|
|
1132
|
-
|
|
1133
|
-
this.openNodeInternal(node, slide, onFinished);
|
|
1134
|
-
return this.element;
|
|
1135
1080
|
}
|
|
1136
1081
|
|
|
1137
|
-
|
|
1138
|
-
|
|
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
|
+
}
|
|
1139
1095
|
|
|
1140
|
-
|
|
1096
|
+
const folderElement = this.createFolderElement(_node);
|
|
1097
|
+
folderElement.open(
|
|
1098
|
+
_onFinished,
|
|
1099
|
+
_slide,
|
|
1100
|
+
this.options.animationSpeed,
|
|
1101
|
+
);
|
|
1102
|
+
};
|
|
1141
1103
|
|
|
1142
|
-
|
|
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;
|
|
1143
1109
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1110
|
+
while (parent) {
|
|
1111
|
+
// nb: do not open root element
|
|
1112
|
+
if (parent.parent) {
|
|
1113
|
+
doOpenNode(parent, false);
|
|
1114
|
+
}
|
|
1115
|
+
parent = parent.parent;
|
|
1116
|
+
}
|
|
1146
1117
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1118
|
+
doOpenNode(node, slide, onFinished);
|
|
1119
|
+
this.saveState();
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1150
1122
|
}
|
|
1151
1123
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
return this.element;
|
|
1155
|
-
}
|
|
1124
|
+
private openParents(node: Node) {
|
|
1125
|
+
const parent = node.parent;
|
|
1156
1126
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1127
|
+
if (parent?.parent && !parent.is_open) {
|
|
1128
|
+
this.openNode(parent, false);
|
|
1129
|
+
}
|
|
1160
1130
|
}
|
|
1161
1131
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
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;
|
|
1166
1141
|
|
|
1167
|
-
this.
|
|
1142
|
+
this.renderer.render(fromNode);
|
|
1168
1143
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1144
|
+
if (mustSelect) {
|
|
1145
|
+
this.selectCurrentNode(mustSetFocus);
|
|
1146
|
+
}
|
|
1171
1147
|
|
|
1172
|
-
|
|
1148
|
+
this.triggerEvent("tree.refresh");
|
|
1173
1149
|
}
|
|
1174
1150
|
|
|
1175
|
-
|
|
1176
|
-
if (
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
if (!node.parent) {
|
|
1181
|
-
throw Error("Node has no parent");
|
|
1151
|
+
private saveState(): void {
|
|
1152
|
+
if (this.options.saveState) {
|
|
1153
|
+
this.saveStateHandler.saveState();
|
|
1182
1154
|
}
|
|
1183
|
-
|
|
1184
|
-
this.selectNodeHandler.removeFromSelection(node, true); // including children
|
|
1185
|
-
|
|
1186
|
-
const parent = node.parent;
|
|
1187
|
-
node.remove();
|
|
1188
|
-
this.refreshElements(parent);
|
|
1189
|
-
|
|
1190
|
-
return this.element;
|
|
1191
1155
|
}
|
|
1192
1156
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1157
|
+
private selectCurrentNode(mustSetFocus: boolean): void {
|
|
1158
|
+
const node = this.getSelectedNode();
|
|
1159
|
+
if (node) {
|
|
1160
|
+
const nodeElement = this.getNodeElementForNode(node);
|
|
1161
|
+
nodeElement.select(mustSetFocus);
|
|
1196
1162
|
}
|
|
1163
|
+
}
|
|
1197
1164
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
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();
|
|
1201
1174
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1175
|
+
if (!state) {
|
|
1176
|
+
return [false, false];
|
|
1177
|
+
} else {
|
|
1178
|
+
const mustLoadOnDemand =
|
|
1179
|
+
this.saveStateHandler.setInitialState(state);
|
|
1205
1180
|
|
|
1206
|
-
|
|
1181
|
+
// return true: the state is restored
|
|
1182
|
+
return [true, mustLoadOnDemand];
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1207
1186
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1187
|
+
const autoOpenNodes = (): boolean => {
|
|
1188
|
+
// result: must load on demand?
|
|
1189
|
+
if (this.options.autoOpen === false) {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1210
1192
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
optionsParam?: SelectNodeOptions,
|
|
1214
|
-
): JQuery {
|
|
1215
|
-
this.doSelectNode(node, optionsParam);
|
|
1216
|
-
return this.element;
|
|
1217
|
-
}
|
|
1193
|
+
const maxLevel = this.getAutoOpenMaxLevel();
|
|
1194
|
+
let mustLoadOnDemand = false;
|
|
1218
1195
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
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
|
+
});
|
|
1223
1207
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
this.saveStateHandler.setInitialState(state);
|
|
1227
|
-
this.refreshElements(null);
|
|
1228
|
-
}
|
|
1208
|
+
return mustLoadOnDemand;
|
|
1209
|
+
};
|
|
1229
1210
|
|
|
1230
|
-
|
|
1231
|
-
}
|
|
1211
|
+
let [isRestored, mustLoadOnDemand] = restoreState(); // eslint-disable-line prefer-const
|
|
1232
1212
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
throw Error(NODE_PARAM_IS_EMPTY);
|
|
1213
|
+
if (!isRestored) {
|
|
1214
|
+
mustLoadOnDemand = autoOpenNodes();
|
|
1236
1215
|
}
|
|
1237
1216
|
|
|
1238
|
-
|
|
1217
|
+
return mustLoadOnDemand;
|
|
1218
|
+
}
|
|
1239
1219
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
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();
|
|
1245
1228
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1229
|
+
if (!state) {
|
|
1230
|
+
return false;
|
|
1231
|
+
} else {
|
|
1232
|
+
this.saveStateHandler.setInitialStateOnDemand(
|
|
1233
|
+
state,
|
|
1234
|
+
cbFinished,
|
|
1235
|
+
);
|
|
1248
1236
|
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1237
|
+
return true;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1252
1241
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
}
|
|
1242
|
+
const autoOpenNodes = (): void => {
|
|
1243
|
+
const maxLevel = this.getAutoOpenMaxLevel();
|
|
1244
|
+
let loadingCount = 0;
|
|
1257
1245
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1246
|
+
const loadAndOpenNode = (node: Node): void => {
|
|
1247
|
+
loadingCount += 1;
|
|
1248
|
+
this.openNodeInternal(node, false, () => {
|
|
1249
|
+
loadingCount -= 1;
|
|
1250
|
+
openNodes();
|
|
1251
|
+
});
|
|
1252
|
+
};
|
|
1261
1253
|
|
|
1262
|
-
|
|
1263
|
-
|
|
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
|
+
}
|
|
1264
1260
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1261
|
+
return false;
|
|
1262
|
+
} else {
|
|
1263
|
+
this.openNodeInternal(node, false);
|
|
1268
1264
|
|
|
1269
|
-
|
|
1265
|
+
return level !== maxLevel;
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1270
1268
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1269
|
+
if (loadingCount === 0) {
|
|
1270
|
+
cbFinished();
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1274
1273
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
data.children &&
|
|
1278
|
-
data.children instanceof Array
|
|
1279
|
-
) {
|
|
1280
|
-
node.removeChildren();
|
|
1274
|
+
openNodes();
|
|
1275
|
+
};
|
|
1281
1276
|
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1277
|
+
if (!restoreState()) {
|
|
1278
|
+
autoOpenNodes();
|
|
1285
1279
|
}
|
|
1280
|
+
}
|
|
1286
1281
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
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;
|
|
1290
1289
|
}
|
|
1291
1290
|
}
|
|
1292
1291
|
|