|
1 | 1 | import { VNode } from '@cycle/dom';
|
2 |
| -import { select } from 'snabbdom-selector'; |
3 |
| -import { EventHandler, MouseOffset, SortableOptions } from '../definitions'; |
4 | 2 |
|
5 |
| -import { |
6 |
| - getIndex, |
7 |
| - getGhostStyle, |
8 |
| - findParent, |
9 |
| - addAttributes, |
10 |
| - addGhostClass, |
11 |
| - replaceNode, |
12 |
| - getBodyStyle, |
13 |
| - addKeys |
14 |
| -} from '../helpers'; |
| 3 | +import { SortableOptions } from '../makeSortable'; |
| 4 | +import { addDataEntry } from '../helpers'; |
15 | 5 |
|
16 |
| -/** |
17 |
| - * Used to create the ghost and hide the item dragged |
18 |
| - * @type {EventHandler} |
19 |
| - */ |
20 |
| -export const mousedownHandler: EventHandler = (node, event, options) => { |
21 |
| - const item: Element = findParent( |
22 |
| - event.target as Element, |
23 |
| - options.parentSelector + ' > *' |
24 |
| - ); |
25 |
| - const itemRect: ClientRect = item.getBoundingClientRect(); |
26 |
| - const parentNode: Element = item.parentElement; |
27 |
| - const parentRect: ClientRect = parentNode.getBoundingClientRect(); |
28 |
| - const mouseOffset: MouseOffset = { |
29 |
| - x: itemRect.left - event.clientX, |
30 |
| - y: itemRect.top - event.clientY, |
31 |
| - itemLeft: itemRect.left, |
32 |
| - itemTop: itemRect.top, |
33 |
| - parentLeft: parentRect.left, |
34 |
| - parentTop: parentRect.top |
35 |
| - }; |
| 6 | +export const selectNames = [ |
| 7 | + '-webkit-touch-callout', |
| 8 | + '-webkit-user-select', |
| 9 | + '-khtml-user-select', |
| 10 | + '-moz-user-select', |
| 11 | + '-ms-user-select', |
| 12 | + 'user-select' |
| 13 | +]; |
36 | 14 |
|
37 |
| - const body: Element = findParent(event.target as Element, 'body'); |
38 |
| - body.setAttribute('style', getBodyStyle()); |
| 15 | +export function mousedownHandler( |
| 16 | + node: VNode, |
| 17 | + ev: MouseEvent, |
| 18 | + opts: SortableOptions |
| 19 | +): VNode { |
| 20 | + const item: Element = ev.currentTarget as Element; |
| 21 | + const indexClicked = [...item.parentElement.children].indexOf(item); |
39 | 22 |
|
40 |
| - const parent: VNode = select(options.parentSelector, node)[0]; |
41 |
| - const index: number = getIndex(item); |
42 |
| - const ghostAttrs: { [name: string]: string } = { |
43 |
| - 'data-mouseoffset': JSON.stringify(mouseOffset), |
44 |
| - 'data-itemdimensions': JSON.stringify({ |
45 |
| - width: itemRect.width, |
46 |
| - height: itemRect.height |
| 23 | + const children = node.children |
| 24 | + .map(addData) |
| 25 | + .map(hideSelected(indexClicked)) |
| 26 | + .concat( |
| 27 | + createGhost(indexClicked, ev, item, node.children[ |
| 28 | + indexClicked |
| 29 | + ] as VNode) |
| 30 | + ); |
| 31 | + |
| 32 | + return { |
| 33 | + ...addDataEntry(node, 'style', { |
| 34 | + ...selectNames |
| 35 | + .map(n => ({ [n]: 'none' })) |
| 36 | + .reduce((a, c) => ({ ...a, ...c }), {}), |
| 37 | + position: 'relative' |
47 | 38 | }),
|
48 |
| - 'data-itemindex': index.toString(), |
49 |
| - 'data-originalIndex': index.toString(), |
50 |
| - style: getGhostStyle(mouseOffset, item) |
| 39 | + children |
51 | 40 | };
|
| 41 | +} |
52 | 42 |
|
53 |
| - const items: VNode[] = parent.children as VNode[]; |
| 43 | +function addData(node: VNode, index: number): VNode { |
| 44 | + return addDataEntry(node, 'dataset', { |
| 45 | + originalIndex: index |
| 46 | + }); |
| 47 | +} |
54 | 48 |
|
55 |
| - const children: VNode[] = [ |
56 |
| - ...items.slice(0, index), |
57 |
| - addAttributes(items[index], { style: 'opacity: 0;' }), |
58 |
| - ...items.slice(index + 1), |
59 |
| - addGhostClass( |
60 |
| - addAttributes({ ...items[index], elm: undefined }, ghostAttrs), |
61 |
| - options.ghostClass |
62 |
| - ) |
63 |
| - ].map((c, i) => addAttributes(c, { 'data-index': i })); |
| 49 | +function hideSelected(index: number): (node: VNode, i: number) => VNode { |
| 50 | + return function(node, i) { |
| 51 | + return i !== index |
| 52 | + ? node |
| 53 | + : addDataEntry(node, 'style', { |
| 54 | + opacity: 0 |
| 55 | + }); |
| 56 | + }; |
| 57 | +} |
64 | 58 |
|
65 |
| - return replaceNode(node, options.parentSelector, { ...parent, children }); |
66 |
| -}; |
| 59 | +function createGhost( |
| 60 | + clicked: number, |
| 61 | + ev: any, |
| 62 | + item: Element, |
| 63 | + node: VNode |
| 64 | +): VNode { |
| 65 | + const rect = item.getBoundingClientRect(); |
| 66 | + const parentRect = item.parentElement.getBoundingClientRect(); |
| 67 | + const offsetX = ev.clientX - rect.left + parentRect.left; |
| 68 | + const offsetY = ev.clientY - rect.top + parentRect.top; |
| 69 | + |
| 70 | + return addDataEntry( |
| 71 | + addDataEntry(node, 'dataset', { |
| 72 | + offsetX, |
| 73 | + offsetY, |
| 74 | + item |
| 75 | + }), |
| 76 | + 'style', |
| 77 | + { |
| 78 | + position: 'absolute', |
| 79 | + left: ev.clientX - offsetX + 'px', |
| 80 | + top: ev.clientY - offsetY + 'px', |
| 81 | + width: rect.width + 'px', |
| 82 | + height: rect.height + 'px', |
| 83 | + 'pointer-events': 'none' |
| 84 | + } |
| 85 | + ); |
| 86 | +} |
0 commit comments