jqtree 1.7.5 → 1.8.0
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/config/babel.config.json +1 -1
- package/config/production +2 -0
- package/devserver/devserver_scroll.js +8 -0
- package/devserver/test_scroll.html +28 -0
- package/devserver/test_scroll_container.html +39 -0
- package/docs/_config.yml +1 -1
- package/docs/_entries/general/changelog.md +7 -0
- package/package.json +5 -1
- package/src/dataLoader.ts +44 -19
- package/src/dragAndDropHandler/dragElement.ts +42 -0
- package/src/dragAndDropHandler/hitAreasGenerator.ts +175 -0
- package/src/dragAndDropHandler/index.ts +470 -0
- package/src/dragAndDropHandler/types.ts +12 -0
- package/src/dragAndDropHandler/visibleNodeIterator.ts +97 -0
- package/src/elementsRenderer.ts +75 -40
- package/src/jqtreeMethodTypes.ts +40 -0
- package/src/jqtreeOptions.ts +43 -25
- package/src/keyHandler.ts +59 -30
- package/src/mouse.widget.ts +3 -3
- package/src/mouseWidgetTypes.ts +6 -0
- package/src/nodeElement/borderDropHint.ts +32 -0
- package/src/nodeElement/folderElement.ts +133 -0
- package/src/nodeElement/ghostDropHint.ts +68 -0
- package/src/nodeElement/index.ts +101 -0
- package/src/playwright/coverage.ts +1 -4
- package/src/playwright/playwright.test.ts +0 -4
- package/src/saveStateHandler.ts +75 -26
- package/src/scrollHandler.ts +13 -7
- package/src/selectNodeHandler.ts +10 -16
- package/src/test/jqTree/keyboard.test.ts +18 -23
- package/src/test/jqTree/methods.test.ts +32 -3
- package/src/test/jqTree/options.test.ts +15 -4
- package/src/test/node.test.ts +1 -1
- package/src/tree.jquery.ts +239 -57
- package/src/util.ts +3 -0
- package/src/version.ts +1 -1
- package/tree.jquery.debug.js +1728 -2576
- package/tree.jquery.debug.js.map +1 -1
- package/tree.jquery.js +2 -2
- package/tree.jquery.js.map +1 -1
- package/lib/dataLoader.js +0 -123
- package/lib/dragAndDropHandler.js +0 -588
- package/lib/elementsRenderer.js +0 -267
- package/lib/jqtreeOptions.js +0 -1
- package/lib/keyHandler.js +0 -111
- package/lib/mouse.widget.js +0 -255
- package/lib/node.js +0 -708
- package/lib/nodeElement.js +0 -274
- package/lib/nodeUtils.js +0 -10
- package/lib/playwright/coverage.js +0 -99
- package/lib/playwright/playwright.test.js +0 -606
- package/lib/playwright/testUtils.js +0 -210
- package/lib/saveStateHandler.js +0 -277
- package/lib/scrollHandler/containerScrollParent.js +0 -160
- package/lib/scrollHandler/createScrollParent.js +0 -57
- package/lib/scrollHandler/documentScrollParent.js +0 -169
- package/lib/scrollHandler/scrollParent.js +0 -58
- package/lib/scrollHandler/types.js +0 -1
- package/lib/scrollHandler.js +0 -71
- package/lib/selectNodeHandler.js +0 -128
- package/lib/simple.widget.js +0 -158
- package/lib/test/global.d.js +0 -3
- package/lib/test/jqTree/accessibility.test.js +0 -37
- package/lib/test/jqTree/create.test.js +0 -48
- package/lib/test/jqTree/events.test.js +0 -210
- package/lib/test/jqTree/keyboard.test.js +0 -225
- package/lib/test/jqTree/loadOnDemand.test.js +0 -218
- package/lib/test/jqTree/methods.test.js +0 -1348
- package/lib/test/jqTree/options.test.js +0 -548
- package/lib/test/jqTree/scrollHandler/containerScrollParent.test.js +0 -94
- package/lib/test/node.test.js +0 -1202
- package/lib/test/nodeUtil.test.js +0 -27
- package/lib/test/nodeUtils.test.js +0 -20
- package/lib/test/support/exampleData.js +0 -35
- package/lib/test/support/jqTreeMatchers.js +0 -70
- package/lib/test/support/matchers.d.js +0 -1
- package/lib/test/support/setupTests.js +0 -7
- package/lib/test/support/testUtil.js +0 -29
- package/lib/test/support/treeStructure.js +0 -38
- package/lib/test/util.test.js +0 -26
- package/lib/tree.jquery.d.js +0 -1
- package/lib/tree.jquery.js +0 -1105
- package/lib/types.js +0 -1
- package/lib/typings.d.js +0 -2
- package/lib/util.js +0 -15
- package/lib/version.js +0 -8
- package/src/dragAndDropHandler.ts +0 -713
- package/src/nodeElement.ts +0 -272
- package/src/types.ts +0 -19
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { getPositionName, Node, Position } from "../node";
|
|
2
|
+
import { DropHint, HitArea } from "./types";
|
|
3
|
+
import { PositionInfo } from "../mouseWidgetTypes";
|
|
4
|
+
import NodeElement from "../nodeElement";
|
|
5
|
+
import DragElement from "./dragElement";
|
|
6
|
+
import HitAreasGenerator from "./hitAreasGenerator";
|
|
7
|
+
import {
|
|
8
|
+
OnCanMove,
|
|
9
|
+
OnCanMoveTo,
|
|
10
|
+
OnIsMoveHandle,
|
|
11
|
+
DragMethod,
|
|
12
|
+
} from "../jqtreeOptions";
|
|
13
|
+
import {
|
|
14
|
+
GetScrollLeft,
|
|
15
|
+
GetTree,
|
|
16
|
+
OpenNode,
|
|
17
|
+
RefreshElements,
|
|
18
|
+
TriggerEvent,
|
|
19
|
+
} from "../jqtreeMethodTypes";
|
|
20
|
+
|
|
21
|
+
interface Dimensions {
|
|
22
|
+
left: number;
|
|
23
|
+
top: number;
|
|
24
|
+
right: number;
|
|
25
|
+
bottom: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type GetNodeElement = (element: HTMLElement) => NodeElement | null;
|
|
29
|
+
type GetNodeElementForNode = (node: Node) => NodeElement;
|
|
30
|
+
|
|
31
|
+
interface DragAndDropHandlerParams {
|
|
32
|
+
autoEscape?: boolean;
|
|
33
|
+
getNodeElement: GetNodeElement;
|
|
34
|
+
getNodeElementForNode: GetNodeElementForNode;
|
|
35
|
+
getScrollLeft: GetScrollLeft;
|
|
36
|
+
getTree: GetTree;
|
|
37
|
+
onCanMove?: OnCanMove;
|
|
38
|
+
onCanMoveTo?: OnCanMoveTo;
|
|
39
|
+
onDragMove?: DragMethod;
|
|
40
|
+
onDragStop?: DragMethod;
|
|
41
|
+
onIsMoveHandle?: OnIsMoveHandle;
|
|
42
|
+
openFolderDelay: number | false;
|
|
43
|
+
openNode: OpenNode;
|
|
44
|
+
refreshElements: RefreshElements;
|
|
45
|
+
slide: boolean;
|
|
46
|
+
$treeElement: JQuery<HTMLElement>;
|
|
47
|
+
triggerEvent: TriggerEvent;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class DragAndDropHandler {
|
|
51
|
+
public hitAreas: HitArea[];
|
|
52
|
+
public isDragging: boolean;
|
|
53
|
+
public currentItem: NodeElement | null;
|
|
54
|
+
public hoveredArea: HitArea | null;
|
|
55
|
+
|
|
56
|
+
private autoEscape?: boolean;
|
|
57
|
+
private dragElement: DragElement | null;
|
|
58
|
+
private getNodeElement: GetNodeElement;
|
|
59
|
+
private getNodeElementForNode: GetNodeElementForNode;
|
|
60
|
+
private getScrollLeft: GetScrollLeft;
|
|
61
|
+
private getTree: GetTree;
|
|
62
|
+
private onCanMove?: OnCanMove;
|
|
63
|
+
private onCanMoveTo?: OnCanMoveTo;
|
|
64
|
+
private onDragMove?: DragMethod;
|
|
65
|
+
private onDragStop?: DragMethod;
|
|
66
|
+
private onIsMoveHandle?: OnIsMoveHandle;
|
|
67
|
+
private openFolderDelay: number | false;
|
|
68
|
+
private openFolderTimer: number | null;
|
|
69
|
+
private openNode: OpenNode;
|
|
70
|
+
private previousGhost: DropHint | null;
|
|
71
|
+
private refreshElements: RefreshElements;
|
|
72
|
+
private slide: boolean;
|
|
73
|
+
private $treeElement: JQuery<HTMLElement>;
|
|
74
|
+
private triggerEvent: TriggerEvent;
|
|
75
|
+
|
|
76
|
+
constructor({
|
|
77
|
+
autoEscape,
|
|
78
|
+
getNodeElement,
|
|
79
|
+
getNodeElementForNode,
|
|
80
|
+
getScrollLeft,
|
|
81
|
+
getTree,
|
|
82
|
+
onCanMove,
|
|
83
|
+
onCanMoveTo,
|
|
84
|
+
onDragMove,
|
|
85
|
+
onDragStop,
|
|
86
|
+
onIsMoveHandle,
|
|
87
|
+
openNode,
|
|
88
|
+
refreshElements,
|
|
89
|
+
slide,
|
|
90
|
+
$treeElement,
|
|
91
|
+
triggerEvent,
|
|
92
|
+
}: DragAndDropHandlerParams) {
|
|
93
|
+
this.autoEscape = autoEscape;
|
|
94
|
+
this.getNodeElement = getNodeElement;
|
|
95
|
+
this.getNodeElementForNode = getNodeElementForNode;
|
|
96
|
+
this.getScrollLeft = getScrollLeft;
|
|
97
|
+
this.getTree = getTree;
|
|
98
|
+
this.onCanMove = onCanMove;
|
|
99
|
+
this.onCanMoveTo = onCanMoveTo;
|
|
100
|
+
this.onDragMove = onDragMove;
|
|
101
|
+
this.onDragStop = onDragStop;
|
|
102
|
+
this.onIsMoveHandle = onIsMoveHandle;
|
|
103
|
+
this.openNode = openNode;
|
|
104
|
+
this.refreshElements = refreshElements;
|
|
105
|
+
this.slide = slide;
|
|
106
|
+
this.$treeElement = $treeElement;
|
|
107
|
+
this.triggerEvent = triggerEvent;
|
|
108
|
+
|
|
109
|
+
this.hoveredArea = null;
|
|
110
|
+
this.hitAreas = [];
|
|
111
|
+
this.isDragging = false;
|
|
112
|
+
this.currentItem = null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public mouseCapture(positionInfo: PositionInfo): boolean | null {
|
|
116
|
+
const element = positionInfo.target;
|
|
117
|
+
|
|
118
|
+
if (!this.mustCaptureElement(element)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (this.onIsMoveHandle && !this.onIsMoveHandle(jQuery(element))) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let nodeElement = this.getNodeElement(element);
|
|
127
|
+
|
|
128
|
+
if (nodeElement && this.onCanMove) {
|
|
129
|
+
if (!this.onCanMove(nodeElement.node)) {
|
|
130
|
+
nodeElement = null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.currentItem = nodeElement;
|
|
135
|
+
return this.currentItem != null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public mouseStart(positionInfo: PositionInfo): boolean {
|
|
139
|
+
if (
|
|
140
|
+
!this.currentItem ||
|
|
141
|
+
positionInfo.pageX === undefined ||
|
|
142
|
+
positionInfo.pageY === undefined
|
|
143
|
+
) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.refresh();
|
|
148
|
+
|
|
149
|
+
const offset = jQuery(positionInfo.target).offset();
|
|
150
|
+
const left = offset ? offset.left : 0;
|
|
151
|
+
const top = offset ? offset.top : 0;
|
|
152
|
+
|
|
153
|
+
const node = this.currentItem.node;
|
|
154
|
+
|
|
155
|
+
this.dragElement = new DragElement(
|
|
156
|
+
node.name,
|
|
157
|
+
positionInfo.pageX - left,
|
|
158
|
+
positionInfo.pageY - top,
|
|
159
|
+
this.$treeElement,
|
|
160
|
+
this.autoEscape ?? true,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
this.isDragging = true;
|
|
164
|
+
this.currentItem.element.classList.add("jqtree-moving");
|
|
165
|
+
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public mouseDrag(positionInfo: PositionInfo): boolean {
|
|
170
|
+
if (
|
|
171
|
+
!this.currentItem ||
|
|
172
|
+
!this.dragElement ||
|
|
173
|
+
positionInfo.pageX === undefined ||
|
|
174
|
+
positionInfo.pageY === undefined
|
|
175
|
+
) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.dragElement.move(positionInfo.pageX, positionInfo.pageY);
|
|
180
|
+
|
|
181
|
+
const area = this.findHoveredArea(
|
|
182
|
+
positionInfo.pageX,
|
|
183
|
+
positionInfo.pageY,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (area && this.canMoveToArea(area)) {
|
|
187
|
+
if (!area.node.isFolder()) {
|
|
188
|
+
this.stopOpenFolderTimer();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.hoveredArea !== area) {
|
|
192
|
+
this.hoveredArea = area;
|
|
193
|
+
|
|
194
|
+
// If this is a closed folder, start timer to open it
|
|
195
|
+
if (this.mustOpenFolderTimer(area)) {
|
|
196
|
+
this.startOpenFolderTimer(area.node);
|
|
197
|
+
} else {
|
|
198
|
+
this.stopOpenFolderTimer();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.updateDropHint();
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
this.removeDropHint();
|
|
205
|
+
this.stopOpenFolderTimer();
|
|
206
|
+
this.hoveredArea = area;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!area) {
|
|
210
|
+
if (this.onDragMove) {
|
|
211
|
+
this.onDragMove(
|
|
212
|
+
this.currentItem.node,
|
|
213
|
+
positionInfo.originalEvent,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public mouseStop(positionInfo: PositionInfo): boolean {
|
|
222
|
+
this.moveItem(positionInfo);
|
|
223
|
+
this.clear();
|
|
224
|
+
this.removeHover();
|
|
225
|
+
this.removeDropHint();
|
|
226
|
+
this.removeHitAreas();
|
|
227
|
+
|
|
228
|
+
const currentItem = this.currentItem;
|
|
229
|
+
|
|
230
|
+
if (this.currentItem) {
|
|
231
|
+
this.currentItem.element.classList.remove("jqtree-moving");
|
|
232
|
+
this.currentItem = null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
this.isDragging = false;
|
|
236
|
+
|
|
237
|
+
if (!this.hoveredArea && currentItem) {
|
|
238
|
+
if (this.onDragStop) {
|
|
239
|
+
this.onDragStop(currentItem.node, positionInfo.originalEvent);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public refresh(): void {
|
|
247
|
+
this.removeHitAreas();
|
|
248
|
+
|
|
249
|
+
if (this.currentItem) {
|
|
250
|
+
this.generateHitAreas();
|
|
251
|
+
|
|
252
|
+
this.currentItem = this.getNodeElementForNode(
|
|
253
|
+
this.currentItem.node,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
if (this.isDragging) {
|
|
257
|
+
this.currentItem.element.classList.add("jqtree-moving");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private generateHitAreas(): void {
|
|
263
|
+
const tree = this.getTree();
|
|
264
|
+
|
|
265
|
+
if (!this.currentItem || !tree) {
|
|
266
|
+
this.hitAreas = [];
|
|
267
|
+
} else {
|
|
268
|
+
const hitAreasGenerator = new HitAreasGenerator(
|
|
269
|
+
tree,
|
|
270
|
+
this.currentItem.node,
|
|
271
|
+
this.getTreeDimensions().bottom,
|
|
272
|
+
);
|
|
273
|
+
this.hitAreas = hitAreasGenerator.generate();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private mustCaptureElement(element: HTMLElement): boolean {
|
|
278
|
+
const nodeName = element.nodeName;
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
nodeName !== "INPUT" &&
|
|
282
|
+
nodeName !== "SELECT" &&
|
|
283
|
+
nodeName !== "TEXTAREA"
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private canMoveToArea(area: HitArea): boolean {
|
|
288
|
+
if (!this.onCanMoveTo) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!this.currentItem) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const positionName = getPositionName(area.position);
|
|
297
|
+
|
|
298
|
+
return this.onCanMoveTo(this.currentItem.node, area.node, positionName);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private removeHitAreas(): void {
|
|
302
|
+
this.hitAreas = [];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private clear(): void {
|
|
306
|
+
if (this.dragElement) {
|
|
307
|
+
this.dragElement.remove();
|
|
308
|
+
this.dragElement = null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private removeDropHint(): void {
|
|
313
|
+
if (this.previousGhost) {
|
|
314
|
+
this.previousGhost.remove();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private removeHover(): void {
|
|
319
|
+
this.hoveredArea = null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private findHoveredArea(x: number, y: number): HitArea | null {
|
|
323
|
+
const dimensions = this.getTreeDimensions();
|
|
324
|
+
|
|
325
|
+
if (
|
|
326
|
+
x < dimensions.left ||
|
|
327
|
+
y < dimensions.top ||
|
|
328
|
+
x > dimensions.right ||
|
|
329
|
+
y > dimensions.bottom
|
|
330
|
+
) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let low = 0;
|
|
335
|
+
let high = this.hitAreas.length;
|
|
336
|
+
while (low < high) {
|
|
337
|
+
const mid = (low + high) >> 1;
|
|
338
|
+
const area = this.hitAreas[mid];
|
|
339
|
+
|
|
340
|
+
if (!area) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (y < area.top) {
|
|
345
|
+
high = mid;
|
|
346
|
+
} else if (y > area.bottom) {
|
|
347
|
+
low = mid + 1;
|
|
348
|
+
} else {
|
|
349
|
+
return area;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private mustOpenFolderTimer(area: HitArea): boolean {
|
|
357
|
+
const node = area.node;
|
|
358
|
+
|
|
359
|
+
return (
|
|
360
|
+
node.isFolder() &&
|
|
361
|
+
!node.is_open &&
|
|
362
|
+
area.position === Position.Inside
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private updateDropHint(): void {
|
|
367
|
+
if (!this.hoveredArea) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// remove previous drop hint
|
|
372
|
+
this.removeDropHint();
|
|
373
|
+
|
|
374
|
+
// add new drop hint
|
|
375
|
+
const nodeElement = this.getNodeElementForNode(this.hoveredArea.node);
|
|
376
|
+
this.previousGhost = nodeElement.addDropHint(this.hoveredArea.position);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private startOpenFolderTimer(folder: Node): void {
|
|
380
|
+
const openFolder = (): void => {
|
|
381
|
+
this.openNode(folder, this.slide, () => {
|
|
382
|
+
this.refresh();
|
|
383
|
+
this.updateDropHint();
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
this.stopOpenFolderTimer();
|
|
388
|
+
|
|
389
|
+
const openFolderDelay = this.openFolderDelay;
|
|
390
|
+
|
|
391
|
+
if (openFolderDelay !== false) {
|
|
392
|
+
this.openFolderTimer = window.setTimeout(
|
|
393
|
+
openFolder,
|
|
394
|
+
openFolderDelay,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
private stopOpenFolderTimer(): void {
|
|
400
|
+
if (this.openFolderTimer) {
|
|
401
|
+
clearTimeout(this.openFolderTimer);
|
|
402
|
+
this.openFolderTimer = null;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private moveItem(positionInfo: PositionInfo): void {
|
|
407
|
+
if (
|
|
408
|
+
this.currentItem &&
|
|
409
|
+
this.hoveredArea &&
|
|
410
|
+
this.hoveredArea.position !== Position.None &&
|
|
411
|
+
this.canMoveToArea(this.hoveredArea)
|
|
412
|
+
) {
|
|
413
|
+
const movedNode = this.currentItem.node;
|
|
414
|
+
const targetNode = this.hoveredArea.node;
|
|
415
|
+
const position = this.hoveredArea.position;
|
|
416
|
+
const previousParent = movedNode.parent;
|
|
417
|
+
|
|
418
|
+
if (position === Position.Inside) {
|
|
419
|
+
this.hoveredArea.node.is_open = true;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const doMove = (): void => {
|
|
423
|
+
const tree = this.getTree();
|
|
424
|
+
|
|
425
|
+
if (tree) {
|
|
426
|
+
tree.moveNode(movedNode, targetNode, position);
|
|
427
|
+
this.$treeElement.empty();
|
|
428
|
+
this.refreshElements(null);
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const event = this.triggerEvent("tree.move", {
|
|
433
|
+
move_info: {
|
|
434
|
+
moved_node: movedNode,
|
|
435
|
+
target_node: targetNode,
|
|
436
|
+
position: getPositionName(position),
|
|
437
|
+
previous_parent: previousParent,
|
|
438
|
+
do_move: doMove,
|
|
439
|
+
original_event: positionInfo.originalEvent,
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
if (!event.isDefaultPrevented()) {
|
|
444
|
+
doMove();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private getTreeDimensions(): Dimensions {
|
|
450
|
+
// Return the dimensions of the tree. Add a margin to the bottom to allow
|
|
451
|
+
// to drag-and-drop after the last element.
|
|
452
|
+
const offset = this.$treeElement.offset();
|
|
453
|
+
|
|
454
|
+
if (!offset) {
|
|
455
|
+
return { left: 0, top: 0, right: 0, bottom: 0 };
|
|
456
|
+
} else {
|
|
457
|
+
const el = this.$treeElement;
|
|
458
|
+
const width = el.width() || 0;
|
|
459
|
+
const height = el.height() || 0;
|
|
460
|
+
const left = offset.left + this.getScrollLeft();
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
left,
|
|
464
|
+
top: offset.top,
|
|
465
|
+
right: left + width,
|
|
466
|
+
bottom: offset.top + height + 16,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Node } from "../node";
|
|
2
|
+
|
|
3
|
+
abstract class VisibleNodeIterator {
|
|
4
|
+
private tree: Node;
|
|
5
|
+
|
|
6
|
+
constructor(tree: Node) {
|
|
7
|
+
this.tree = tree;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
protected iterate(): void {
|
|
11
|
+
let isFirstNode = true;
|
|
12
|
+
|
|
13
|
+
const _iterateNode = (node: Node, nextNode: Node | null): void => {
|
|
14
|
+
let mustIterateInside =
|
|
15
|
+
(node.is_open || !node.element) && node.hasChildren();
|
|
16
|
+
|
|
17
|
+
let element: HTMLElement | null = null;
|
|
18
|
+
|
|
19
|
+
// Is the element visible?
|
|
20
|
+
if (node.element?.offsetParent) {
|
|
21
|
+
element = node.element;
|
|
22
|
+
|
|
23
|
+
if (isFirstNode) {
|
|
24
|
+
this.handleFirstNode(node);
|
|
25
|
+
isFirstNode = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!node.hasChildren()) {
|
|
29
|
+
this.handleNode(node, nextNode, node.element);
|
|
30
|
+
} else if (node.is_open) {
|
|
31
|
+
if (!this.handleOpenFolder(node, node.element)) {
|
|
32
|
+
mustIterateInside = false;
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
this.handleClosedFolder(node, nextNode, element);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (mustIterateInside) {
|
|
40
|
+
const childrenLength = node.children.length;
|
|
41
|
+
node.children.forEach((_, i) => {
|
|
42
|
+
const child = node.children[i];
|
|
43
|
+
|
|
44
|
+
if (child) {
|
|
45
|
+
if (i === childrenLength - 1) {
|
|
46
|
+
_iterateNode(child, null);
|
|
47
|
+
} else {
|
|
48
|
+
const nextChild = node.children[i + 1];
|
|
49
|
+
|
|
50
|
+
if (nextChild) {
|
|
51
|
+
_iterateNode(child, nextChild);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (node.is_open && element) {
|
|
58
|
+
this.handleAfterOpenFolder(node, nextNode);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
_iterateNode(this.tree, null);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected abstract handleNode(
|
|
67
|
+
node: Node,
|
|
68
|
+
nextNode: Node | null,
|
|
69
|
+
element: HTMLElement,
|
|
70
|
+
): void;
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
override
|
|
74
|
+
return
|
|
75
|
+
- true: continue iterating
|
|
76
|
+
- false: stop iterating
|
|
77
|
+
*/
|
|
78
|
+
protected abstract handleOpenFolder(
|
|
79
|
+
node: Node,
|
|
80
|
+
element: HTMLElement,
|
|
81
|
+
): boolean;
|
|
82
|
+
|
|
83
|
+
protected abstract handleClosedFolder(
|
|
84
|
+
node: Node,
|
|
85
|
+
nextNode: Node | null,
|
|
86
|
+
element: HTMLElement,
|
|
87
|
+
): void;
|
|
88
|
+
|
|
89
|
+
protected abstract handleAfterOpenFolder(
|
|
90
|
+
node: Node,
|
|
91
|
+
nextNode: Node | null,
|
|
92
|
+
): void;
|
|
93
|
+
|
|
94
|
+
protected abstract handleFirstNode(node: Node): void;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default VisibleNodeIterator;
|