aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableColumn.tsx
blob: 28d2e6ab1da66e92564054d93baad4e6c9fc8d16 (plain)
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>
        );
    }
}