import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import autobind from 'autobind-decorator'; import ReactDOM from 'react-dom'; import { DragSource, DropTarget } from 'react-dnd'; import classnames from 'classnames'; import Highlight from '../base/highlight'; import RequestGroupActionsDropdown from '../dropdowns/request-group-actions-dropdown'; import SidebarRequestRow from './sidebar-request-row'; import * as misc from '../../../common/misc'; @autobind class SidebarRequestGroupRow extends PureComponent { constructor(props) { super(props); this.state = { dragDirection: 0, }; } _setRequestGroupActionsDropdownRef(n) { this._requestGroupActionsDropdown = n; } _setExpandTagRef(n) { this._expandTag = n; } getExpandTag() { return this._expandTag; } _handleCollapse() { const { requestGroup, handleSetRequestGroupCollapsed, isCollapsed } = this.props; handleSetRequestGroupCollapsed(requestGroup._id, !isCollapsed); } _handleShowActions(e) { e.preventDefault(); this._requestGroupActionsDropdown.show(); } setDragDirection(dragDirection) { if (dragDirection !== this.state.dragDirection) { this.setState({ dragDirection }); } } render() { const { connectDragSource, connectDropTarget, filter, moveDoc, children, requestGroup, isCollapsed, isActive, handleCreateRequest, handleCreateRequestGroup, handleDuplicateRequestGroup, handleMoveRequestGroup, isDragging, isDraggingOver, workspace, hotKeyRegistry, activeEnvironment, } = this.props; const { dragDirection } = this.state; let folderIconClass = 'fa-folder'; folderIconClass += isCollapsed ? '' : '-open'; folderIconClass += isActive ? '' : '-o'; const classes = classnames('sidebar__row', { 'sidebar__row--dragging': isDragging, 'sidebar__row--dragging-above': isDraggingOver && dragDirection > 0, 'sidebar__row--dragging-below': isDraggingOver && dragDirection < 0, }); // NOTE: We only want the button draggable, not the whole container (ie. no children) const button = connectDragSource( connectDropTarget( , ), ); return (
  • {button}
  • ); } } SidebarRequestGroupRow.propTypes = { // Functions handleSetRequestGroupCollapsed: PropTypes.func.isRequired, handleDuplicateRequestGroup: PropTypes.func.isRequired, handleMoveRequestGroup: PropTypes.func.isRequired, moveDoc: PropTypes.func.isRequired, handleActivateRequest: PropTypes.func.isRequired, handleCreateRequest: PropTypes.func.isRequired, handleCreateRequestGroup: PropTypes.func.isRequired, // Other filter: PropTypes.string.isRequired, isActive: PropTypes.bool.isRequired, isCollapsed: PropTypes.bool.isRequired, workspace: PropTypes.object.isRequired, requestGroup: PropTypes.object.isRequired, hotKeyRegistry: PropTypes.object.isRequired, // React DnD isDragging: PropTypes.bool, isDraggingOver: PropTypes.bool, connectDragSource: PropTypes.func, connectDropTarget: PropTypes.func, // Optional children: PropTypes.node, activeEnvironment: PropTypes.object, }; /** * Implements the drag source contract. */ const dragSource = { beginDrag(props) { return { requestGroup: props.requestGroup, }; }, }; function isAbove(monitor, component) { const hoveredNode = ReactDOM.findDOMNode(component); const hoveredTop = hoveredNode.getBoundingClientRect().top; const draggedTop = monitor.getSourceClientOffset().y; return hoveredTop > draggedTop; } function isOnExpandTag(monitor, component) { const rect = component.getExpandTag().getBoundingClientRect(); const pointer = monitor.getClientOffset(); return ( rect.left <= pointer.x && pointer.x <= rect.right && rect.top <= pointer.y && pointer.y <= rect.bottom ); } const dragTarget = { drop(props, monitor, component) { const movingDoc = monitor.getItem().requestGroup || monitor.getItem().request; const parentId = props.requestGroup.parentId; const targetId = props.requestGroup._id; if (isAbove(monitor, component)) { props.moveDoc(movingDoc, parentId, targetId, 1); } else { props.moveDoc(movingDoc, parentId, targetId, -1); } }, hover(props, monitor, component) { if (props.isCollapsed && isOnExpandTag(monitor, component)) { component.props.handleSetRequestGroupCollapsed(props.requestGroup._id, false); component.setDragDirection(0); } else if (isAbove(monitor, component)) { component.setDragDirection(1); } else { component.setDragDirection(-1); } }, }; function sourceCollect(connect, monitor) { return { connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), }; } function targetCollect(connect, monitor) { return { connectDropTarget: connect.dropTarget(), isDraggingOver: monitor.isOver(), }; } const source = DragSource('SIDEBAR_REQUEST_ROW', dragSource, sourceCollect)(SidebarRequestGroupRow); export default DropTarget('SIDEBAR_REQUEST_ROW', dragTarget, targetCollect)(source);