/* * This file is part of ORY Editor. * * ORY Editor is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ORY Editor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with ORY Editor. If not, see . * * @license LGPL-3.0 * @copyright 2016-2018 Aeneas Rekkas * @author Aeneas Rekkas * */ import * as React from 'react'; import throttle from 'lodash.throttle'; import pathOr from 'ramda/src/pathOr'; import { computeAndDispatchHover, computeAndDispatchInsert } from '../../../../service/hover/input'; import { delay } from '../../../../helper/throttle'; import logger from '../../../../service/logger'; import { isNativeHTMLElementDrag, createNativeCellReplacement } from '../../../../helper/nativeDragHelpers'; import { DropTargetMonitor, DropTargetConnector } from 'dnd-core'; import { ComponetizedCell } from '../../../../types/editable'; let last: { hover: string; drag: string } = { hover: '', drag: '' }; const clear = (hover: ComponetizedCell, drag: string) => { if (hover.id === last.hover && drag === last.drag) { return; } last = { hover: hover.id, drag }; hover.clearHover(); }; export const target = { hover: throttle( ( hover: ComponetizedCell, monitor: DropTargetMonitor, component: React.ReactInstance ) => { // tslint:disable-next-line:no-any let drag: any = monitor.getItem(); if (!drag) { // item undefined, happens when throttle triggers after drop return; } if (isNativeHTMLElementDrag(monitor)) { drag = createNativeCellReplacement(); } if (drag.id === hover.id) { // If hovering over itself, do nothing clear(hover, drag.id); return; } else if (!monitor.isOver({ shallow: true })) { // If hovering over ancestor cell, do nothing (we are going to propagate later in the tree anyways) return; } else if (hover.ancestors.indexOf(drag.id) > -1) { // If hovering over a child of itself clear(hover, drag.id); return; } else if (!hover.id) { // If hovering over something that isn't a cell or hasn't an id, do nothing. Should be an edge case logger.warn('Canceled cell drop, no id given.', hover, drag); return; } last = { hover: hover.id, drag: drag.id }; const allowInlineNeighbours = pathOr( false, ['node', 'content', 'plugin', 'allowInlineNeighbours'], hover ); computeAndDispatchHover( hover, drag, monitor, component, `10x10${allowInlineNeighbours ? '' : '-no-inline'}` ); }, delay, { leading: false } ), canDrop: ( { id, ancestors }: ComponetizedCell, monitor: DropTargetMonitor ) => { const item = monitor.getItem(); return item.id !== id && ancestors.indexOf(item.id) === -1; }, // tslint:disable-next-line:no-any drop(hover: ComponetizedCell, monitor: DropTargetMonitor, component: any) { let drag: ComponetizedCell = monitor.getItem(); if (isNativeHTMLElementDrag(monitor)) { const { plugins } = component.props.config; drag = plugins.createNativePlugin(hover, monitor, component); } if (monitor.didDrop() || !monitor.isOver({ shallow: true })) { // If the item drop occurred deeper down the tree, don't do anything return; } else if (drag.id === hover.id) { // If the item being dropped on itself do nothing hover.cancelCellDrag(); return; } else if (hover.ancestors.indexOf(drag.id) > -1) { // If hovering over a child of itself, don't propagate further hover.cancelCellDrag(); return; } last = { hover: hover.id, drag: drag.id }; const allowInlineNeighbours = pathOr( false, ['node', 'content', 'plugin', 'allowInlineNeighbours'], hover ); computeAndDispatchInsert( hover, drag, monitor, component, `10x10${allowInlineNeighbours ? '' : '-no-inline'}` ); }, }; export const connect = ( connectInner: DropTargetConnector, monitor: DropTargetMonitor ) => ({ connectDropTarget: connectInner.dropTarget(), isOver: monitor.isOver(), isOverCurrent: monitor.isOver({ shallow: true }), });