1717
1818import React from "react" ;
1919import PropTypes from "prop-types" ;
20- import { DragSource } from "react-dnd" ;
20+ import { DragSource , DropTarget } from "react-dnd" ;
2121import classNames from "classnames" ;
2222import { modifier } from "modifier-keys" ;
2323import Callstack from "../Callstack" ;
@@ -28,20 +28,92 @@ import MoreButton from "../ActionButtons/More";
2828import "./style.css" ;
2929
3030export const Type = "test" ;
31+
3132const testSource = {
3233 beginDrag ( props ) {
3334 return {
3435 id : props . test . id ,
35- suite : props . suite . id
36+ index : props . index ,
37+ test : props . test ,
38+ suite : props . suite
3639 } ;
40+ } ,
41+ isDragging ( props , monitor ) {
42+ return ( props . test . id === monitor . getItem ( ) . id && props . suite . id === monitor . getItem ( ) . suite . id ) ;
3743 }
3844} ;
39- function collect ( connect , monitor ) {
45+
46+ function collectSource ( connect , monitor ) {
4047 return {
4148 connectDragSource : connect . dragSource ( ) ,
4249 isDragging : monitor . isDragging ( )
4350 } ;
4451}
52+
53+ const testTarget = {
54+ canDrop ( props , monitor ) {
55+ const test = monitor . getItem ( ) . test ;
56+ const suite = props . suite ;
57+ return ! suite . containsTest ( test ) ;
58+ } ,
59+ hover ( props , monitor , component ) {
60+ // check if they are different suites
61+ const dragged = monitor . getItem ( ) ;
62+ if ( monitor . canDrop ( ) && props . suite !== dragged . suite ) {
63+ dragged . suite . removeTestCase ( dragged . test ) ;
64+ props . suite . addTestCase ( dragged . test ) ;
65+ dragged . suite = props . suite ;
66+ dragged . index = props . suite . tests . length - 1 ;
67+ return ;
68+ } else if ( ! monitor . canDrop ( ) && props . suite !== dragged . suite ) {
69+ // trying to move a duplicate
70+ return ;
71+ }
72+ const dragIndex = dragged . index ;
73+ const hoverIndex = props . index ;
74+
75+ // Don't replace items with themselves
76+ if ( dragIndex === hoverIndex ) {
77+ return ;
78+ }
79+
80+ // Determine rectangle on screen
81+ const hoverBoundingRect = component . decoratedComponentInstance . node . getBoundingClientRect ( ) ;
82+
83+ // Get vertical middle
84+ const hoverMiddleY = ( hoverBoundingRect . bottom - hoverBoundingRect . top ) / 2 ;
85+
86+ // Determine mouse position
87+ const clientOffset = monitor . getClientOffset ( ) ;
88+
89+ // Get pixels to the top
90+ const hoverClientY = clientOffset . y - hoverBoundingRect . top ;
91+
92+ // Only perform the move when the mouse has crossed half of the items height
93+ // When dragging downwards, only move when the cursor is below 50%
94+ // When dragging upwards, only move when the cursor is above 50%
95+
96+ // Dragging downwards
97+ if ( dragIndex < hoverIndex && hoverClientY < hoverMiddleY ) {
98+ return ;
99+ }
100+
101+ // Dragging upwards
102+ if ( dragIndex > hoverIndex && hoverClientY > hoverMiddleY ) {
103+ return ;
104+ }
105+
106+ props . swapTests ( dragIndex , hoverIndex ) ;
107+
108+ // save time on index lookups
109+ monitor . getItem ( ) . index = hoverIndex ;
110+ }
111+ } ;
112+
113+ const collectTarget = ( connect ) => ( {
114+ connectDropTarget : connect . dropTarget ( )
115+ } ) ;
116+
45117export default class Test extends React . Component {
46118 static propTypes = {
47119 className : PropTypes . string ,
@@ -58,6 +130,7 @@ export default class Test extends React.Component {
58130 selectTest : PropTypes . func . isRequired ,
59131 renameTest : PropTypes . func ,
60132 removeTest : PropTypes . func ,
133+ connectDropTarget : PropTypes . func ,
61134 connectDragSource : PropTypes . func ,
62135 moveSelectionUp : PropTypes . func ,
63136 moveSelectionDown : PropTypes . func ,
@@ -127,7 +200,7 @@ export default class Test extends React.Component {
127200 tabIndex = { this . props . selected ? "0" : "-1" }
128201 onContextMenu = { this . props . onContextMenu }
129202 style = { {
130- display : this . props . isDragging ? "none " : "block "
203+ opacity : this . props . isDragging ? "0 " : "1 "
131204 } } >
132205 < a
133206 ref = { ( button ) => { this . button = button ; } }
@@ -144,7 +217,7 @@ export default class Test extends React.Component {
144217 onClick = { this . handleCallstackClick . bind ( this , this . props . test , this . props . suite ) }
145218 /> : undefined }
146219 </ div > ;
147- return ( this . props . connectDragSource ? this . props . connectDragSource ( rendered ) : rendered ) ;
220+ return ( this . props . connectDragSource ? this . props . connectDropTarget ( this . props . connectDragSource ( rendered ) ) : rendered ) ;
148221 }
149222}
150223
@@ -164,4 +237,5 @@ export class MenuTest extends React.Component {
164237 }
165238}
166239
167- export const DraggableTest = DragSource ( Type , testSource , collect ) ( Test ) ;
240+
241+ export const DraggableTest = DropTarget ( Type , testTarget , collectTarget ) ( DragSource ( Type , testSource , collectSource ) ( Test ) ) ;
0 commit comments