@@ -43,29 +43,21 @@ export class DraggingPositionEvaluation {
4343 this . targetItem = this . env . linearItems [ this . treeId ] [ this . linearIndex ] ;
4444 }
4545
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+ }
6855
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 ( ) {
6961 const redirectTargetToParent =
7062 ! this . env . canReorderItems &&
7163 ! this . env . canDropOnNonFolder &&
@@ -77,17 +69,13 @@ export class DraggingPositionEvaluation {
7769 this . targetItem = parent ;
7870 this . linearIndex = parentLinearIndex ;
7971 }
72+ }
8073
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 {
9179 const treeLinearItems = this . env . linearItems [ this . treeId ] ;
9280 const deepestDepth = treeLinearItems [ this . linearIndex ] . depth ;
9381 const legalDropDepthCount = // itemDepthDifferenceToNextItem/isLastInGroup
@@ -96,84 +84,171 @@ export class DraggingPositionEvaluation {
9684 this . offset === 'bottom' && legalDropDepthCount > 0 ;
9785 // Default to zero on last position to allow dropping on root when
9886 // 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
103108 ) ;
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+ }
114110
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 ;
118113 }
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 ) ;
119128
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 ( ) {
120151 const nextItem = this . env . linearItems [ this . treeId ] [ this . linearIndex + 1 ] ;
121- const redirectToFirstChild =
152+ const redirectInsideOpenFolder =
122153 ! this . env . canDropBelowOpenFolders &&
123154 nextItem &&
124155 this . targetItem . depth === nextItem . depth - 1 &&
125156 this . offset === 'bottom' ;
126- if ( redirectToFirstChild ) {
157+ if ( redirectInsideOpenFolder ) {
127158 this . targetItem = nextItem ;
128159 this . linearIndex += 1 ;
129160 this . offset = 'top' ;
130161 }
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+ }
131178
132- const { depth } = this . targetItem ;
179+ private canDropAtCurrentTarget ( ) {
133180 const targetItemData = this . env . items [ this . targetItem . item ] ;
134181
135182 if (
136183 ! this . offset &&
137184 ! this . env . canDropOnNonFolder &&
138185 ! targetItemData . isFolder
139186 ) {
140- return undefined ;
187+ return false ;
141188 }
142189
143190 if ( ! this . offset && ! this . env . canDropOnFolder && targetItemData . isFolder ) {
144- return undefined ;
191+ return false ;
145192 }
146193
147194 if ( this . offset && ! this . env . canReorderItems ) {
148- return undefined ;
195+ return false ;
149196 }
150197
151- const { parent } = this . evaluator . getParentOfLinearItem (
152- this . linearIndex ,
153- this . treeId
154- ) ;
155-
156198 if (
157- this . evaluator . draggingItems . some (
199+ this . evaluator . draggingItems ? .some (
158200 draggingItem => draggingItem . index === this . targetItem . item
159201 )
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
160218 ) {
161219 return undefined ;
162220 }
163221
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+ ) ;
164240 const newChildIndex =
165241 this . env . items [ parent . item ] . children ! . indexOf ( this . targetItem . item ) +
166242 ( this . offset === 'top' ? 0 : 1 ) ;
167243
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 ;
175248 }
176249
250+ // used to be here: this.maybeMapToBottomOffset();.. moved up for better readability
251+
177252 if ( this . offset ) {
178253 return {
179254 targetType : 'between-items' ,
@@ -215,4 +290,15 @@ export class DraggingPositionEvaluation {
215290
216291 return this . isDescendant ( treeId , parentLinearIndex , potentialParents ) ;
217292 }
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+ }
218304}
0 commit comments