1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
import React = require('react');
import { action } from 'mobx';
import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
import { DragManager } from '../../../util/DragManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import './CollectionSchemaView.scss';
export interface MovableColumnProps {
columnRenderer: React.ReactNode;
columnValue: SchemaHeaderField;
allColumns: SchemaHeaderField[];
reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
ScreenToLocalTransform: () => Transform;
}
export class MovableColumn extends React.Component<MovableColumnProps> {
// The header of the column
private _header?: React.RefObject<HTMLDivElement> = React.createRef();
// The container of the function that is responsible for moving the column over to a new plac
private _colDropDisposer?: DragManager.DragDropDisposer;
// initial column position
private _startDragPosition: { x: number; y: number } = { x: 0, y: 0 };
// sensitivity to being dragged, in pixels
private _sensitivity: number = 16;
// Column reference ID
private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
onPointerEnter = (e: React.PointerEvent): void => {
// if the column is left-clicked and it is being dragged
if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
this._header!.current!.className = 'collectionSchema-col-wrapper';
document.addEventListener('pointermove', this.onDragMove, true);
}
};
onPointerLeave = (e: React.PointerEvent): void => {
this._header!.current!.className = 'collectionSchema-col-wrapper';
document.removeEventListener('pointermove', this.onDragMove, true);
!e.buttons && document.removeEventListener('pointermove', this.onPointerMove);
};
onDragMove = (e: PointerEvent): void => {
// only take into account the horizonal direction when a column is dragged
const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
const rect = this._header!.current!.getBoundingClientRect();
// Now store the point at the top center of the column when it was in its original position
const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top);
// to be compared with its new horizontal position
const before = x[0] < bounds[0];
this._header!.current!.className = 'collectionSchema-col-wrapper';
if (before) this._header!.current!.className += ' col-before';
if (!before) this._header!.current!.className += ' col-after';
e.stopPropagation();
};
createColDropTarget = (ele: HTMLDivElement) => {
this._colDropDisposer?.();
if (ele) {
this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
}
};
colDrop = (e: Event, de: DragManager.DropEvent) => {
document.removeEventListener('pointermove', this.onDragMove, true);
// we only care about whether the column is shifted to the side
const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
// get the dimensions of the smallest rectangle that bounds the header
const rect = this._header!.current!.getBoundingClientRect();
const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top);
// get whether the column was dragged before or after where it is now
const before = x[0] < bounds[0];
const colDragData = de.complete.columnDragData;
// if there is colDragData, which happen when the drag is complete, reorder the columns according to the established variables
if (colDragData) {
e.stopPropagation();
this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns);
return true;
}
return false;
};
onPointerMove = (e: PointerEvent) => {
const onRowMove = (e: PointerEvent) => {
e.stopPropagation();
e.preventDefault();
document.removeEventListener('pointermove', onRowMove);
document.removeEventListener('pointerup', onRowUp);
const dragData = new DragManager.ColumnDragData(this.props.columnValue);
DragManager.StartColumnDrag(this._dragRef.current!, dragData, e.x, e.y);
};
const onRowUp = (): void => {
document.removeEventListener('pointermove', onRowMove);
document.removeEventListener('pointerup', onRowUp);
};
// if the left mouse button is the one being held
if (e.buttons === 1) {
const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
// If the movemnt of the drag exceeds the sensitivity value
if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
document.removeEventListener('pointermove', this.onPointerMove);
e.stopPropagation();
document.addEventListener('pointermove', onRowMove);
document.addEventListener('pointerup', onRowUp);
}
}
};
onPointerUp = (e: React.PointerEvent) => {
document.removeEventListener('pointermove', this.onPointerMove);
};
@action
onPointerDown = (e: React.PointerEvent, ref: React.RefObject<HTMLDivElement>) => {
this._dragRef = ref;
const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY);
// If the cell thing dragged is not being edited
if (!(e.target as any)?.tagName.includes('INPUT')) {
this._startDragPosition = { x: dx, y: dy };
document.addEventListener('pointermove', this.onPointerMove);
}
};
render() {
const reference = React.createRef<HTMLDivElement>();
return (
<div className="collectionSchema-col" ref={this.createColDropTarget}>
<div className="collectionSchema-col-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
<div className="col-dragger" ref={reference} onPointerDown={e => this.onPointerDown(e, reference)} onPointerUp={this.onPointerUp}>
{this.props.columnRenderer}
</div>
</div>
</div>
);
}
}
|