@@ -17,14 +17,19 @@ import InstanceManager from '../../../../../src/manager/Instance.mjs';
1717 * @summary Tests for Neo.draggable.dashboard.SortZone directional thresholds
1818 */
1919test . describe . serial ( 'Neo.draggable.dashboard.SortZone Directional Logic' , ( ) => {
20- let DashboardSortZone , Rectangle , sortZone ;
20+ let DashboardContainer , DashboardSortZone , Rectangle , realDragCoordinatorOnDragEnd , sortZone ;
2121
2222 test . beforeAll ( async ( ) => {
23+ const containerModule = await import ( '../../../../../src/dashboard/Container.mjs' ) ;
24+ DashboardContainer = containerModule . default ;
25+
2326 const sortZoneModule = await import ( '../../../../../src/draggable/dashboard/SortZone.mjs' ) ;
2427 DashboardSortZone = sortZoneModule . default ;
2528
2629 const rectModule = await import ( '../../../../../src/util/Rectangle.mjs' ) ;
2730 Rectangle = rectModule . default ;
31+
32+ realDragCoordinatorOnDragEnd = Object . getPrototypeOf ( Neo . manager . DragCoordinator ) . onDragEnd ;
2833 } ) ;
2934
3035 test . beforeEach ( ( ) => {
@@ -188,6 +193,130 @@ test.describe.serial('Neo.draggable.dashboard.SortZone Directional Logic', () =>
188193 expect ( sortZone . isWindowDragging ) . toBe ( false )
189194 } ) ;
190195
196+ test ( 'keeps a terminal popup drop detached instead of running remote-drop cleanup (#13025)' , async ( ) => {
197+ const
198+ appliedDeltas = [ ] ,
199+ terminalDrops = [ ] ,
200+ DragCoordinator = Neo . manager . DragCoordinator ,
201+ item = {
202+ id : 'item1' ,
203+ reference : 'item1' ,
204+ vdom : { cls : [ 'neo-draggable' ] } ,
205+ wrapperStyle : { }
206+ } ,
207+ placeholder = {
208+ id : 'placeholder' ,
209+ vdom : { cls : [ ] } ,
210+ wrapperStyle : { } ,
211+ destroy : ( ) => { }
212+ } ,
213+ detachedItems = new Map ( [ [ 'item1' , {
214+ index : 0 ,
215+ widget : item ,
216+ windowId : 'popup-item1'
217+ } ] ] ) ,
218+ mockOwner = {
219+ id : 'mockOwner' ,
220+ cls : [ ] ,
221+ detachedItems,
222+ dragResortable : true ,
223+ items : [ item , placeholder ] ,
224+ style : { } ,
225+ vdom : { } ,
226+ addDomListeners : ( ) => { } ,
227+ getDomRect : ( ) => Promise . resolve ( [ { x :0 , y :0 , width :200 , height :100 } ] ) ,
228+ getVdomItemsRoot : ( ) => ( { id : 'mockOwner-items' } ) ,
229+ on : ( ) => { } ,
230+ onWindowDragTerminalDrop : data => terminalDrops . push ( data )
231+ } ;
232+
233+ Neo . applyDeltas = ( windowId , deltas ) => {
234+ appliedDeltas . push ( ...deltas ) ;
235+ return Promise . resolve ( )
236+ } ;
237+
238+ DragCoordinator . activeTargetZone = null ;
239+ DragCoordinator . onDragEnd = data => realDragCoordinatorOnDragEnd . call ( DragCoordinator , data ) ;
240+
241+ sortZone = Neo . create ( DashboardSortZone , {
242+ owner : mockOwner ,
243+ timeout : ( ) => Promise . resolve ( )
244+ } ) ;
245+
246+ Object . assign ( sortZone , {
247+ currentIndex : 1 ,
248+ dragComponent : item ,
249+ dragPlaceholder : placeholder ,
250+ dragProxy : { id : 'proxy' , cls : [ ] , destroy : ( ) => { } } ,
251+ isWindowDragging : true ,
252+ itemRects : [
253+ { height : 100 , left : 0 , top : 0 , width : 100 } ,
254+ { height : 100 , left : 100 , top : 0 , width : 100 }
255+ ] ,
256+ itemStyles : [
257+ { height : '100px' , width : '100px' } ,
258+ { height : '100px' , width : '100px' }
259+ ] ,
260+ ownerStyle : { } ,
261+ sortableItems : [ item , placeholder ] ,
262+ startIndex : 0 ,
263+ windowId : 1
264+ } ) ;
265+
266+ await sortZone . processDragEnd ( { type : 'drag:end' } ) ;
267+
268+ expect ( terminalDrops ) . toHaveLength ( 1 ) ;
269+ expect ( terminalDrops [ 0 ] . draggedItem ) . toBe ( item ) ;
270+ expect ( terminalDrops [ 0 ] . sortZone ) . toBe ( sortZone ) ;
271+ expect ( detachedItems . has ( 'item1' ) ) . toBe ( true ) ;
272+ expect ( appliedDeltas . some ( delta => delta . action === 'moveNode' && delta . id === item . id ) ) . toBe ( false ) ;
273+ expect ( appliedDeltas . some ( delta => delta . action === 'removeNode' && delta . id === placeholder . id ) ) . toBe ( true ) ;
274+ expect ( sortZone . isWindowDragging ) . toBe ( false )
275+ } ) ;
276+
277+ test ( 'does not classify an ordinary source-window drag end as a terminal popup drop (#13025)' , ( ) => {
278+ const
279+ DragCoordinator = Neo . manager . DragCoordinator ,
280+ sourceSortZone = {
281+ isWindowDragging : false ,
282+ onTerminalWindowDrop : ( ) => {
283+ throw new Error ( 'ordinary drag-end should not terminal-drop' )
284+ }
285+ } ;
286+
287+ DragCoordinator . activeTargetZone = null ;
288+
289+ realDragCoordinatorOnDragEnd . call ( DragCoordinator , {
290+ draggedItem : { id : 'item1' } ,
291+ sourceSortZone
292+ } )
293+ } ) ;
294+
295+ test ( 'marks dashboard detached items as terminal popup drops (#13025)' , ( ) => {
296+ const
297+ item = { id : 'item1' , reference : 'item1' } ,
298+ detachedItem = { index : 0 , widget : item , windowId : 'popup-item1' } ,
299+ detachedItems = new Map ( [ [ 'item1' , detachedItem ] ] ) ,
300+ events = [ ] ,
301+ container = Object . create ( DashboardContainer . prototype ) ;
302+
303+ Object . assign ( container , {
304+ detachedItems,
305+ fire : ( event , data ) => events . push ( { data, event} )
306+ } ) ;
307+
308+ container . onWindowDragTerminalDrop ( {
309+ draggedItem : item ,
310+ sortZone : { id : 'source-zone' }
311+ } ) ;
312+
313+ expect ( detachedItems . get ( 'item1' ) ) . toBe ( detachedItem ) ;
314+ expect ( detachedItem . terminalDrop ) . toBe ( true ) ;
315+ expect ( events ) . toHaveLength ( 1 ) ;
316+ expect ( events [ 0 ] . event ) . toBe ( 'windowDragTerminalDrop' ) ;
317+ expect ( events [ 0 ] . data . detachedItem ) . toBe ( detachedItem )
318+ } ) ;
319+
191320 test ( 'latches dashboard drag-end coordinator notification (#12895)' , async ( ) => {
192321 const
193322 dragEndCalls = [ ] ,
0 commit comments