Skip to content

Commit c58da86

Browse files
committed
[IMP] Selection: convert grid drag-n-drop into a hook
Task: 3582335
1 parent cead7c1 commit c58da86

18 files changed

Lines changed: 291 additions & 213 deletions

File tree

src/components/autofill/autofill.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AUTOFILL_EDGE_LENGTH } from "../../constants";
33
import { clip } from "../../helpers";
44
import { HeaderIndex, SpreadsheetChildEnv } from "../../types";
55
import { css, cssPropertiesToCss } from "../helpers/css";
6-
import { dragAndDropBeyondTheViewport } from "../helpers/drag_and_drop";
6+
import { useDragAndDropBeyondTheViewport } from "../helpers/drag_and_drop_grid_hook";
77

88
// -----------------------------------------------------------------------------
99
// Autofill
@@ -64,6 +64,8 @@ export class Autofill extends Component<Props, SpreadsheetChildEnv> {
6464
handler: false,
6565
});
6666

67+
dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
68+
6769
get style() {
6870
const { left, top } = this.props.position;
6971
return cssPropertiesToCss({
@@ -96,7 +98,7 @@ export class Autofill extends Component<Props, SpreadsheetChildEnv> {
9698
return tooltip;
9799
}
98100

99-
onMouseDown(ev: MouseEvent) {
101+
onMouseDown(ev: PointerEvent) {
100102
this.state.handler = true;
101103

102104
let lastCol: HeaderIndex | undefined;
@@ -127,7 +129,7 @@ export class Autofill extends Component<Props, SpreadsheetChildEnv> {
127129
}
128130
}
129131
};
130-
dragAndDropBeyondTheViewport(this.env, onMouseMove, onMouseUp);
132+
this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
131133
}
132134

133135
onDblClick() {

src/components/bottom_bar/bottom_bar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { _t } from "../../translation";
66
import { MenuMouseEvent, Pixel, Rect, SpreadsheetChildEnv, UID } from "../../types";
77
import { Ripple } from "../animation/ripple";
88
import { css } from "../helpers/css";
9-
import { useDragAndDropListItems } from "../helpers/drag_and_drop_hook";
9+
import { useDragAndDropListItems } from "../helpers/drag_and_drop_dom_items_hook";
1010
import { Menu, MenuState } from "../menu/menu";
1111
import { BottomBarSheet } from "./bottom_bar_sheet/bottom_bar_sheet";
1212
import { BottomBarStatistic } from "./bottom_bar_statistic/bottom_bar_statistic";

src/components/grid/grid.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ import { GridPopover } from "../grid_popover/grid_popover";
6666
import { HeadersOverlay } from "../headers_overlay/headers_overlay";
6767
import { cssPropertiesToCss } from "../helpers";
6868
import { keyboardEventToShortcutString } from "../helpers/dom_helpers";
69-
import { dragAndDropBeyondTheViewport } from "../helpers/drag_and_drop";
69+
import { useDragAndDropBeyondTheViewport } from "../helpers/drag_and_drop_grid_hook";
7070
import { useGridDrawing } from "../helpers/draw_grid_hook";
7171
import { useAbsoluteBoundingRect } from "../helpers/position_hook";
7272
import { updateSelectionWithArrowKeys } from "../helpers/selection_helpers";
@@ -144,6 +144,8 @@ export class Grid extends Component<Props, SpreadsheetChildEnv> {
144144
private DOMFocusableElementStore!: Store<DOMFocusableElementStore>;
145145
private paintFormatStore!: Store<PaintFormatStore>;
146146

147+
dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
148+
147149
onMouseWheel!: (ev: WheelEvent) => void;
148150
canvasPosition!: DOMCoordinates;
149151
hoveredCell!: Store<HoveredCellStore>;
@@ -475,7 +477,13 @@ export class Grid extends Component<Props, SpreadsheetChildEnv> {
475477
// Zone selection with mouse
476478
// ---------------------------------------------------------------------------
477479

478-
onCellClicked(col: HeaderIndex, row: HeaderIndex, modifiers: GridClickModifiers) {
480+
onCellClicked(
481+
col: HeaderIndex,
482+
row: HeaderIndex,
483+
modifiers: GridClickModifiers,
484+
ev: PointerEvent
485+
) {
486+
ev.preventDefault();
479487
if (this.composerFocusStore.activeComposer.editionMode === "editing") {
480488
this.composerFocusStore.activeComposer.stopEdition();
481489
}
@@ -505,7 +513,7 @@ export class Grid extends Component<Props, SpreadsheetChildEnv> {
505513
this.paintFormatStore.pasteFormat(this.env.model.getters.getSelectedZones());
506514
}
507515
};
508-
dragAndDropBeyondTheViewport(this.env, onMouseMove, onMouseUp);
516+
this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
509517
}
510518

511519
onCellDoubleClicked(col: HeaderIndex, row: HeaderIndex) {

src/components/grid_overlay/grid_overlay.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,12 @@ function useTouchMove(
164164
interface Props {
165165
onCellHovered: (position: Partial<Position>) => void;
166166
onCellDoubleClicked: (col: HeaderIndex, row: HeaderIndex) => void;
167-
onCellClicked: (col: HeaderIndex, row: HeaderIndex, modifiers: GridClickModifiers) => void;
167+
onCellClicked: (
168+
col: HeaderIndex,
169+
row: HeaderIndex,
170+
modifiers: GridClickModifiers,
171+
ev: MouseEvent
172+
) => void;
168173
onCellRightClicked: (col: HeaderIndex, row: HeaderIndex, coordinates: DOMCoordinates) => void;
169174
onGridResized: (dimension: Rect) => void;
170175
onGridMoved: (deltaX: Pixel, deltaY: Pixel) => void;
@@ -252,10 +257,15 @@ export class GridOverlay extends Component<Props, SpreadsheetChildEnv> {
252257
this.cellPopovers.close();
253258
}
254259
const [col, row] = this.getCartesianCoordinates(ev);
255-
this.props.onCellClicked(col, row, {
256-
expandZone: ev.shiftKey,
257-
addZone: isCtrlKey(ev),
258-
});
260+
this.props.onCellClicked(
261+
col,
262+
row,
263+
{
264+
expandZone: ev.shiftKey,
265+
addZone: isCtrlKey(ev),
266+
},
267+
ev
268+
);
259269
}
260270

261271
onDoubleClick(ev: MouseEvent) {

src/components/headers_overlay/headers_overlay.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
import { ContextMenuType } from "../grid/grid";
2323
import { css, cssPropertiesToCss } from "../helpers/css";
2424
import { isCtrlKey } from "../helpers/dom_helpers";
25-
import { dragAndDropBeyondTheViewport, startDnd } from "../helpers/drag_and_drop";
25+
import { startDnd } from "../helpers/drag_and_drop";
26+
import { useDragAndDropBeyondTheViewport } from "../helpers/drag_and_drop_grid_hook";
2627
import { MergeErrorMessage } from "../translations_terms";
2728
import { ComposerFocusStore } from "./../composer/composer_focus_store";
2829
import { UnhideColumnHeaders, UnhideRowHeaders } from "./unhide_headers";
@@ -76,6 +77,8 @@ abstract class AbstractResizer extends Component<ResizerProps, SpreadsheetChildE
7677
position: "before",
7778
});
7879

80+
dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
81+
7982
abstract _getEvOffset(ev: MouseEvent): Pixel;
8083

8184
abstract _getViewportOffset(): Pixel;
@@ -202,7 +205,7 @@ abstract class AbstractResizer extends Component<ResizerProps, SpreadsheetChildE
202205
startDnd(onMouseMove, onMouseUp);
203206
}
204207

205-
select(ev: MouseEvent) {
208+
select(ev: PointerEvent) {
206209
if (ev.button > 0) {
207210
// not main button, probably a context menu
208211
return;
@@ -227,7 +230,7 @@ abstract class AbstractResizer extends Component<ResizerProps, SpreadsheetChildE
227230
this.startSelection(ev, index);
228231
}
229232

230-
private startMovement(ev: MouseEvent) {
233+
private startMovement(ev: PointerEvent) {
231234
this.state.waitingForMove = false;
232235
this.state.isMoving = true;
233236
const startDimensions = this._getDimensionsInViewport(this._getSelectedZoneStart());
@@ -266,10 +269,10 @@ abstract class AbstractResizer extends Component<ResizerProps, SpreadsheetChildE
266269
}
267270
this._computeGrabDisplay(ev);
268271
};
269-
dragAndDropBeyondTheViewport(this.env, mouseMoveMovement, mouseUpMovement);
272+
this.dragNDropGrid.start(ev, mouseMoveMovement, mouseUpMovement);
270273
}
271274

272-
private startSelection(ev: MouseEvent, index: HeaderIndex) {
275+
private startSelection(ev: PointerEvent, index: HeaderIndex) {
273276
this.state.isSelecting = true;
274277
if (ev.shiftKey) {
275278
this._increaseSelection(index);
@@ -290,7 +293,7 @@ abstract class AbstractResizer extends Component<ResizerProps, SpreadsheetChildE
290293
this.lastSelectedElementIndex = null;
291294
this._computeGrabDisplay(ev);
292295
};
293-
dragAndDropBeyondTheViewport(this.env, mouseMoveSelect, mouseUpSelect);
296+
this.dragNDropGrid.start(ev, mouseMoveSelect, mouseUpSelect);
294297
}
295298

296299
onMouseUp(ev: MouseEvent) {
Lines changed: 10 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,176 +1,31 @@
1-
import { MAX_DELAY } from "../../helpers";
2-
import { SpreadsheetChildEnv } from "../../types/env";
3-
import { HeaderIndex } from "../../types/misc";
4-
import { gridOverlayPosition } from "./dom_helpers";
5-
type EventFn = (ev: MouseEvent) => void;
1+
type EventFn = (ev: PointerEvent) => void;
62

73
/**
84
* Start listening to pointer events and apply the given callbacks.
95
*
106
* @returns A function to remove the listeners.
117
*/
12-
export function startDnd(
13-
onMouseMove: EventFn,
14-
onMouseUp: EventFn,
15-
onMouseDown: EventFn = () => {}
16-
) {
8+
export function startDnd(onPointerMove: EventFn, onPointerUp: EventFn) {
179
const removeListeners = () => {
18-
window.removeEventListener("pointerdown", onMouseDown);
19-
window.removeEventListener("pointerup", _onMouseUp);
10+
window.removeEventListener("pointerup", _onPointerUp);
2011
window.removeEventListener("dragstart", _onDragStart);
21-
window.removeEventListener("pointermove", onMouseMove);
22-
window.removeEventListener("wheel", onMouseMove);
12+
window.removeEventListener("pointermove", onPointerMove);
13+
window.removeEventListener("wheel", onPointerMove);
2314
};
24-
const _onMouseUp = (ev: MouseEvent) => {
25-
onMouseUp(ev);
15+
const _onPointerUp = (ev: PointerEvent) => {
16+
onPointerUp(ev);
2617
removeListeners();
2718
};
2819
function _onDragStart(ev: DragEvent) {
2920
ev.preventDefault();
3021
}
31-
window.addEventListener("pointerdown", onMouseDown);
32-
window.addEventListener("pointerup", _onMouseUp);
22+
window.addEventListener("pointerup", _onPointerUp);
3323
window.addEventListener("dragstart", _onDragStart);
34-
window.addEventListener("pointermove", onMouseMove);
24+
window.addEventListener("pointermove", onPointerMove);
3525
// mouse wheel on window is by default a passive event.
3626
// preventDefault() is not allowed in passive event handler.
3727
// https://chromestatus.com/feature/6662647093133312
38-
window.addEventListener("wheel", onMouseMove, { passive: false });
28+
window.addEventListener("wheel", onPointerMove, { passive: false });
3929

4030
return removeListeners;
4131
}
42-
43-
/**
44-
* Function to be used during a pointerdown event, this function allows to
45-
* perform actions related to the pointermove and pointerup events and adjusts the viewport
46-
* when the new position related to the pointermove event is outside of it.
47-
* Among inputs are two callback functions. First intended for actions performed during
48-
* the pointermove event, it receives as parameters the current position of the pointermove
49-
* (occurrence of the current column and the current row). Second intended for actions
50-
* performed during the pointerup event.
51-
*/
52-
export function dragAndDropBeyondTheViewport(
53-
env: SpreadsheetChildEnv,
54-
cbMouseMove: (col: HeaderIndex, row: HeaderIndex, ev: MouseEvent) => void,
55-
cbMouseUp: () => void,
56-
only: "horizontal" | "vertical" | false = false
57-
) {
58-
let timeOutId: any = null;
59-
let currentEv: MouseEvent;
60-
let previousEv: MouseEvent;
61-
let startingEv: MouseEvent;
62-
let startingX: number;
63-
let startingY: number;
64-
const getters = env.model.getters;
65-
const sheetId = getters.getActiveSheetId();
66-
const position = gridOverlayPosition();
67-
let colIndex: number;
68-
let rowIndex: number;
69-
const onMouseDown = (ev: MouseEvent) => {
70-
previousEv = ev;
71-
startingEv = ev;
72-
startingX = startingEv.clientX - position.left;
73-
startingY = startingEv.clientY - position.top;
74-
};
75-
const onMouseMove = (ev: MouseEvent) => {
76-
currentEv = ev;
77-
if (timeOutId) {
78-
return;
79-
}
80-
81-
const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
82-
let { top, left, bottom, right } = getters.getActiveMainViewport();
83-
let { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
84-
const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
85-
let canEdgeScroll = false;
86-
let timeoutDelay = MAX_DELAY;
87-
88-
const x = currentEv.clientX - position.left;
89-
colIndex = getters.getColIndex(x);
90-
91-
if (only !== "vertical") {
92-
const previousX = previousEv.clientX - position.left;
93-
const edgeScrollInfoX = getters.getEdgeScrollCol(x, previousX, startingX);
94-
if (edgeScrollInfoX.canEdgeScroll) {
95-
canEdgeScroll = true;
96-
timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoX.delay);
97-
let newTarget: number;
98-
switch (edgeScrollInfoX.direction) {
99-
case "reset":
100-
colIndex = xSplit;
101-
newTarget = xSplit;
102-
break;
103-
case 1:
104-
colIndex = right;
105-
newTarget = left + 1;
106-
break;
107-
case -1:
108-
colIndex = left - 1;
109-
while (env.model.getters.isColHidden(sheetId, colIndex)) {
110-
colIndex--;
111-
}
112-
newTarget = colIndex;
113-
break;
114-
}
115-
scrollX = getters.getColDimensions(sheetId, newTarget!).start - offsetCorrectionX;
116-
}
117-
}
118-
119-
const y = currentEv.clientY - position.top;
120-
rowIndex = getters.getRowIndex(y);
121-
122-
if (only !== "horizontal") {
123-
const previousY = previousEv.clientY - position.top;
124-
const edgeScrollInfoY = getters.getEdgeScrollRow(y, previousY, startingY);
125-
if (edgeScrollInfoY.canEdgeScroll) {
126-
canEdgeScroll = true;
127-
timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoY.delay);
128-
let newTarget: number;
129-
switch (edgeScrollInfoY.direction) {
130-
case "reset":
131-
rowIndex = ySplit;
132-
newTarget = ySplit;
133-
break;
134-
case 1:
135-
rowIndex = bottom;
136-
newTarget = top + edgeScrollInfoY.direction;
137-
break;
138-
case -1:
139-
rowIndex = top - 1;
140-
while (env.model.getters.isRowHidden(sheetId, rowIndex)) {
141-
rowIndex--;
142-
}
143-
newTarget = rowIndex;
144-
break;
145-
}
146-
scrollY = env.model.getters.getRowDimensions(sheetId, newTarget!).start - offsetCorrectionY;
147-
}
148-
}
149-
150-
if (!canEdgeScroll) {
151-
if (rowIndex === -1) {
152-
rowIndex = y < 0 ? 0 : getters.getNumberRows(sheetId) - 1;
153-
}
154-
if (colIndex === -1 && x < 0) {
155-
colIndex = x < 0 ? 0 : getters.getNumberCols(sheetId) - 1;
156-
}
157-
}
158-
159-
cbMouseMove(colIndex, rowIndex, currentEv);
160-
if (canEdgeScroll) {
161-
env.model.dispatch("SET_VIEWPORT_OFFSET", { offsetX: scrollX, offsetY: scrollY });
162-
timeOutId = setTimeout(() => {
163-
timeOutId = null;
164-
onMouseMove(currentEv);
165-
}, Math.round(timeoutDelay));
166-
}
167-
previousEv = currentEv;
168-
};
169-
170-
const onMouseUp = () => {
171-
clearTimeout(timeOutId);
172-
cbMouseUp();
173-
};
174-
175-
startDnd(onMouseMove, onMouseUp, onMouseDown);
176-
}
File renamed without changes.

0 commit comments

Comments
 (0)