@@ -43,29 +43,21 @@ export class DraggingPositionEvaluation {
43
43
this . targetItem = this . env . linearItems [ this . treeId ] [ this . linearIndex ] ;
44
44
}
45
45
46
- getDraggingPosition ( ) : DraggingPosition | undefined {
47
- if ( ! this . evaluator . draggingItems ) {
48
- return undefined ;
49
- }
50
-
51
- if ( this . env . linearItems [ this . treeId ] . length === 0 ) {
52
- // Empty tree
53
- return {
54
- targetType : 'root' ,
55
- treeId : this . treeId ,
56
- depth : 0 ,
57
- linearIndex : 0 ,
58
- targetItem : this . env . trees [ this . treeId ] . rootItem ,
59
- } ;
60
- }
61
-
62
- if (
63
- this . linearIndex < 0 ||
64
- this . linearIndex >= this . env . linearItems [ this . treeId ] . length
65
- ) {
66
- return undefined ;
67
- }
46
+ private getEmptyTreeDragPosition ( ) : DraggingPosition {
47
+ return {
48
+ targetType : 'root' ,
49
+ treeId : this . treeId ,
50
+ depth : 0 ,
51
+ linearIndex : 0 ,
52
+ targetItem : this . env . trees [ this . treeId ] . rootItem ,
53
+ } ;
54
+ }
68
55
56
+ /**
57
+ * If reordering is not allowed, dragging on non-folder items redirects
58
+ * the drag target to the parent of the target item.
59
+ */
60
+ private maybeRedirectToParent ( ) {
69
61
const redirectTargetToParent =
70
62
! this . env . canReorderItems &&
71
63
! this . env . canDropOnNonFolder &&
@@ -77,17 +69,13 @@ export class DraggingPositionEvaluation {
77
69
this . targetItem = parent ;
78
70
this . linearIndex = parentLinearIndex ;
79
71
}
72
+ }
80
73
81
- if (
82
- this . isDescendant (
83
- this . treeId ,
84
- this . linearIndex ,
85
- this . evaluator . draggingItems
86
- )
87
- ) {
88
- return undefined ;
89
- }
90
-
74
+ /**
75
+ * If the item is the last in a group, and the drop is at the bottom,
76
+ * the x-coordinate of the mouse allows to reparent upwards.
77
+ */
78
+ private maybeReparentUpwards ( ) : DraggingPosition | undefined {
91
79
const treeLinearItems = this . env . linearItems [ this . treeId ] ;
92
80
const deepestDepth = treeLinearItems [ this . linearIndex ] . depth ;
93
81
const legalDropDepthCount = // itemDepthDifferenceToNextItem/isLastInGroup
@@ -96,84 +84,171 @@ export class DraggingPositionEvaluation {
96
84
this . offset === 'bottom' && legalDropDepthCount > 0 ;
97
85
// Default to zero on last position to allow dropping on root when
98
86
// dropping at bottom
99
- if ( canReparentUpwards ) {
100
- const droppingIndent = Math . max (
101
- deepestDepth - legalDropDepthCount ,
102
- this . indentation
87
+
88
+ if ( ! canReparentUpwards ) {
89
+ return undefined ;
90
+ }
91
+
92
+ const droppingIndent = Math . max (
93
+ deepestDepth - legalDropDepthCount ,
94
+ this . indentation
95
+ ) ;
96
+
97
+ let newParent = {
98
+ parentLinearIndex : this . linearIndex ,
99
+ parent : this . targetItem ,
100
+ } ;
101
+ let insertionItemAbove : typeof newParent | undefined ;
102
+
103
+ for ( let i = deepestDepth ; i >= droppingIndent ; i -= 1 ) {
104
+ insertionItemAbove = newParent ;
105
+ newParent = this . evaluator . getParentOfLinearItem (
106
+ newParent . parentLinearIndex ,
107
+ this . treeId
103
108
) ;
104
- let newParent = {
105
- parentLinearIndex : this . linearIndex ,
106
- parent : this . targetItem ,
107
- } ;
108
- for ( let i = deepestDepth ; i !== droppingIndent ; i -= 1 ) {
109
- newParent = this . evaluator . getParentOfLinearItem (
110
- newParent . parentLinearIndex ,
111
- this . treeId
112
- ) ;
113
- }
109
+ }
114
110
115
- if ( this . indentation !== treeLinearItems [ this . linearIndex ] . depth ) {
116
- this . targetItem = newParent . parent ;
117
- }
111
+ if ( this . indentation === treeLinearItems [ this . linearIndex ] . depth ) {
112
+ return undefined ;
118
113
}
114
+ if ( ! insertionItemAbove ) {
115
+ return undefined ;
116
+ }
117
+
118
+ // this.targetItem = newParent.parent;
119
+ const reparentedChildIndex =
120
+ this . env . items [ newParent . parent . item ] . children ! . indexOf (
121
+ insertionItemAbove . parent . item
122
+ ) + 1 ;
123
+ console . log (
124
+ `new parent is ${ newParent . parent . item } , target is ${ this . targetItem . item } and reparentedChildIndex is ${ reparentedChildIndex } }`
125
+ ) ;
126
+ console . log ( newParent ) ;
127
+ console . log ( 'new depth is' , newParent . parent . depth + 1 ) ;
119
128
129
+ return {
130
+ targetType : 'between-items' ,
131
+ treeId : this . treeId ,
132
+ // parentItem: this.evaluator.getParentOfLinearItem(
133
+ // newParent.parentLinearIndex,
134
+ // this.treeId
135
+ // ).parent.item,
136
+ parentItem : newParent . parent . item ,
137
+ // depth: newParent.parent.depth + 1,
138
+ depth : droppingIndent ,
139
+ linearIndex : this . linearIndex + 1 ,
140
+ childIndex : reparentedChildIndex ,
141
+ linePosition : 'bottom' ,
142
+ } as const ;
143
+ }
144
+
145
+ /**
146
+ * Don't allow to drop at bottom of an open folder, since that will place
147
+ * it visually at a different position. Redirect the drag target to the
148
+ * top of the folder contents in that case.
149
+ */
150
+ private maybeRedirectInsideOpenFolder ( ) {
120
151
const nextItem = this . env . linearItems [ this . treeId ] [ this . linearIndex + 1 ] ;
121
- const redirectToFirstChild =
152
+ const redirectInsideOpenFolder =
122
153
! this . env . canDropBelowOpenFolders &&
123
154
nextItem &&
124
155
this . targetItem . depth === nextItem . depth - 1 &&
125
156
this . offset === 'bottom' ;
126
- if ( redirectToFirstChild ) {
157
+ if ( redirectInsideOpenFolder ) {
127
158
this . targetItem = nextItem ;
128
159
this . linearIndex += 1 ;
129
160
this . offset = 'top' ;
130
161
}
162
+ }
163
+
164
+ /**
165
+ * Inside a folder, only drop at bottom offset to make it visually
166
+ * consistent.
167
+ */
168
+ private maybeMapToBottomOffset ( ) {
169
+ const priorItem = this . env . linearItems [ this . treeId ] [ this . linearIndex - 1 ] ;
170
+ if (
171
+ this . offset === 'top' &&
172
+ this . targetItem . depth === ( priorItem ?. depth ?? - 1 )
173
+ ) {
174
+ this . offset = 'bottom' ;
175
+ this . linearIndex -= 1 ;
176
+ }
177
+ }
131
178
132
- const { depth } = this . targetItem ;
179
+ private canDropAtCurrentTarget ( ) {
133
180
const targetItemData = this . env . items [ this . targetItem . item ] ;
134
181
135
182
if (
136
183
! this . offset &&
137
184
! this . env . canDropOnNonFolder &&
138
185
! targetItemData . isFolder
139
186
) {
140
- return undefined ;
187
+ return false ;
141
188
}
142
189
143
190
if ( ! this . offset && ! this . env . canDropOnFolder && targetItemData . isFolder ) {
144
- return undefined ;
191
+ return false ;
145
192
}
146
193
147
194
if ( this . offset && ! this . env . canReorderItems ) {
148
- return undefined ;
195
+ return false ;
149
196
}
150
197
151
- const { parent } = this . evaluator . getParentOfLinearItem (
152
- this . linearIndex ,
153
- this . treeId
154
- ) ;
155
-
156
198
if (
157
- this . evaluator . draggingItems . some (
199
+ this . evaluator . draggingItems ? .some (
158
200
draggingItem => draggingItem . index === this . targetItem . item
159
201
)
202
+ ) {
203
+ return false ;
204
+ }
205
+
206
+ return true ;
207
+ }
208
+
209
+ getDraggingPosition ( ) : DraggingPosition | undefined {
210
+ if ( this . env . linearItems [ this . treeId ] . length === 0 ) {
211
+ return this . getEmptyTreeDragPosition ( ) ;
212
+ }
213
+
214
+ if (
215
+ ! this . evaluator . draggingItems ||
216
+ this . linearIndex < 0 ||
217
+ this . linearIndex >= this . env . linearItems [ this . treeId ] . length
160
218
) {
161
219
return undefined ;
162
220
}
163
221
222
+ this . maybeRedirectToParent ( ) ;
223
+
224
+ if ( this . areDraggingItemsDescendantOfTarget ( ) ) {
225
+ return undefined ;
226
+ }
227
+
228
+ const reparented = this . maybeReparentUpwards ( ) ;
229
+ if ( reparented ) {
230
+ return reparented ;
231
+ }
232
+
233
+ this . maybeRedirectInsideOpenFolder ( ) ;
234
+
235
+ // Must run before maybeMapToBottomOffset
236
+ const { parent } = this . evaluator . getParentOfLinearItem (
237
+ this . linearIndex ,
238
+ this . treeId
239
+ ) ;
164
240
const newChildIndex =
165
241
this . env . items [ parent . item ] . children ! . indexOf ( this . targetItem . item ) +
166
242
( this . offset === 'top' ? 0 : 1 ) ;
167
243
168
- if (
169
- this . offset === 'top' &&
170
- depth ===
171
- ( this . env . linearItems [ this . treeId ] [ this . linearIndex - 1 ] ?. depth ?? - 1 )
172
- ) {
173
- this . offset = 'bottom' ;
174
- this . linearIndex -= 1 ;
244
+ this . maybeMapToBottomOffset ( ) ;
245
+
246
+ if ( ! this . canDropAtCurrentTarget ( ) ) {
247
+ return undefined ;
175
248
}
176
249
250
+ // used to be here: this.maybeMapToBottomOffset();.. moved up for better readability
251
+
177
252
if ( this . offset ) {
178
253
return {
179
254
targetType : 'between-items' ,
@@ -215,4 +290,15 @@ export class DraggingPositionEvaluation {
215
290
216
291
return this . isDescendant ( treeId , parentLinearIndex , potentialParents ) ;
217
292
}
293
+
294
+ private areDraggingItemsDescendantOfTarget ( ) {
295
+ return (
296
+ this . evaluator . draggingItems &&
297
+ this . isDescendant (
298
+ this . treeId ,
299
+ this . linearIndex ,
300
+ this . evaluator . draggingItems
301
+ )
302
+ ) ;
303
+ }
218
304
}
0 commit comments