Skip to content

Commit 90cb965

Browse files
authored
refactor: Migrate to PointerEvents (RaspberryPiFoundation#6598)
* refactor: Remove checks for PointerEvent support. * refactor: Deprecate and remove calls to splitEventByTouches. * refactor: Deprecate and remove calls to setClientFromTouch(). * refactor: Use PointerEvent in place of Event/MouseEvent/TouchEvent/PseudoEvent. * refactor: Update references to mouse/touch events in code and documentation to reference pointer events. * refactor: Merge Gesture and TouchGesture * chore: clang-format changed files * refactor: Bind and expect PointerEvents instead of MouseEvents. * refactor: Rename TouchGesture to Gesture. * fix: Fix test failures. * chore: clang-format changed files. * fix: Fix errant _ from merging * refactor: Clean up dead code in browser_events.ts. * chore: Update version in deprecation notices to reflect release schedule * fix: Fixed a bug that caused the browser context menu to not be suppressed in Chrome. * fix: Re-export Gesture as TouchGesture for backwards compatibility. * refactor: Deprecate and remove uses of opt_noPreventDefault. * chore: Fix error message in gesture.ts. * chore: Removed obsolete todo.
1 parent 9741cd2 commit 90cb965

30 files changed

Lines changed: 538 additions & 799 deletions

core/block_dragger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export class BlockDragger implements IBlockDragger {
176176
* @param currentDragDeltaXY How far the pointer has moved from the position
177177
* at the start of the drag, in pixel units.
178178
*/
179-
drag(e: Event, currentDragDeltaXY: Coordinate) {
179+
drag(e: PointerEvent, currentDragDeltaXY: Coordinate) {
180180
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
181181
const newLoc = Coordinate.sum(this.startXY_, delta);
182182
this.draggingBlock_.moveDuringDrag(newLoc);
@@ -205,11 +205,11 @@ export class BlockDragger implements IBlockDragger {
205205
/**
206206
* Finish a block drag and put the block back on the workspace.
207207
*
208-
* @param e The mouseup/touchend event.
208+
* @param e The pointerup event.
209209
* @param currentDragDeltaXY How far the pointer has moved from the position
210210
* at the start of the drag, in pixel units.
211211
*/
212-
endDrag(e: Event, currentDragDeltaXY: Coordinate) {
212+
endDrag(e: PointerEvent, currentDragDeltaXY: Coordinate) {
213213
// Make sure internal state is fresh.
214214
this.drag(e, currentDragDeltaXY);
215215
this.dragIconData_ = [];

core/block_svg.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg,
227227
this.pathObject.updateMovable(this.isMovable());
228228
const svg = this.getSvgRoot();
229229
if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) {
230-
browserEvents.conditionalBind(svg, 'mousedown', this, this.onMouseDown_);
230+
browserEvents.conditionalBind(
231+
svg, 'pointerdown', this, this.onMouseDown_);
231232
}
232233
this.eventsInit_ = true;
233234

@@ -673,11 +674,11 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg,
673674
}
674675

675676
/**
676-
* Handle a mouse-down on an SVG block.
677+
* Handle a pointerdown on an SVG block.
677678
*
678-
* @param e Mouse down event or touch start event.
679+
* @param e Pointer down event.
679680
*/
680-
private onMouseDown_(e: Event) {
681+
private onMouseDown_(e: PointerEvent) {
681682
const gesture = this.workspace.getGesture(e);
682683
if (gesture) {
683684
gesture.handleBlockStart(e, this);

core/blockly.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ import {Toolbox} from './toolbox/toolbox.js';
145145
import {ToolboxItem} from './toolbox/toolbox_item.js';
146146
import * as Tooltip from './tooltip.js';
147147
import * as Touch from './touch.js';
148-
import {TouchGesture} from './touch_gesture.js';
149148
import {Trashcan} from './trashcan.js';
150149
import * as utils from './utils.js';
151150
import * as colour from './utils/colour.js';
@@ -485,9 +484,7 @@ export function unbindEvent_(bindData: browserEvents.Data): Function {
485484
* @param opt_noCaptureIdentifier True if triggering on this event should not
486485
* block execution of other event handlers on this touch or other
487486
* simultaneous touches. False by default.
488-
* @param opt_noPreventDefault True if triggering on this event should prevent
489-
* the default handler. False by default. If opt_noPreventDefault is
490-
* provided, opt_noCaptureIdentifier must also be provided.
487+
* @param _opt_noPreventDefault No-op, deprecated and will be removed in v10.
491488
* @returns Opaque data that can be passed to unbindEvent_.
492489
* @deprecated Use **Blockly.browserEvents.conditionalBind** instead.
493490
* @see browserEvents.conditionalBind
@@ -496,13 +493,12 @@ export function unbindEvent_(bindData: browserEvents.Data): Function {
496493
export function bindEventWithChecks_(
497494
node: EventTarget, name: string, thisObject: Object|null, func: Function,
498495
opt_noCaptureIdentifier?: boolean,
499-
opt_noPreventDefault?: boolean): browserEvents.Data {
496+
_opt_noPreventDefault?: boolean): browserEvents.Data {
500497
deprecation.warn(
501498
'Blockly.bindEventWithChecks_', 'December 2021', 'December 2022',
502499
'Blockly.browserEvents.conditionalBind');
503500
return browserEvents.conditionalBind(
504-
node, name, thisObject, func, opt_noCaptureIdentifier,
505-
opt_noPreventDefault);
501+
node, name, thisObject, func, opt_noCaptureIdentifier);
506502
}
507503

508504
// Aliases to allow external code to access these values for legacy reasons.
@@ -671,6 +667,7 @@ export {FlyoutMetricsManager};
671667
export {CodeGenerator};
672668
export {CodeGenerator as Generator}; // Deprecated name, October 2022.
673669
export {Gesture};
670+
export {Gesture as TouchGesture}; // Remove in v10.
674671
export {Grid};
675672
export {HorizontalFlyout};
676673
export {IASTNodeLocation};
@@ -723,7 +720,6 @@ export {Toolbox};
723720
export {ToolboxCategory};
724721
export {ToolboxItem};
725722
export {ToolboxSeparator};
726-
export {TouchGesture};
727723
export {Trashcan};
728724
export {VariableMap};
729725
export {VariableModel};

core/browser_events.ts

Lines changed: 13 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as goog from '../closure/goog/goog.js';
1313
goog.declareModuleId('Blockly.browserEvents');
1414

1515
import * as Touch from './touch.js';
16+
import * as deprecation from './utils/deprecation.js';
1617
import * as userAgent from './utils/useragent.js';
1718

1819

@@ -51,42 +52,36 @@ const PAGE_MODE_MULTIPLIER = 125;
5152
* @param opt_noCaptureIdentifier True if triggering on this event should not
5253
* block execution of other event handlers on this touch or other
5354
* simultaneous touches. False by default.
54-
* @param opt_noPreventDefault True if triggering on this event should prevent
55-
* the default handler. False by default. If opt_noPreventDefault is
56-
* provided, opt_noCaptureIdentifier must also be provided.
55+
* @param opt_noPreventDefault No-op, deprecated and will be removed in v10.
5756
* @returns Opaque data that can be passed to unbindEvent_.
5857
* @alias Blockly.browserEvents.conditionalBind
5958
*/
6059
export function conditionalBind(
6160
node: EventTarget, name: string, thisObject: Object|null, func: Function,
6261
opt_noCaptureIdentifier?: boolean, opt_noPreventDefault?: boolean): Data {
63-
let handled = false;
62+
if (opt_noPreventDefault !== undefined) {
63+
deprecation.warn(
64+
'The opt_noPreventDefault argument of conditionalBind', 'version 9',
65+
'version 10');
66+
}
6467
/**
6568
*
6669
* @param e
6770
*/
6871
function wrapFunc(e: Event) {
6972
const captureIdentifier = !opt_noCaptureIdentifier;
70-
// Handle each touch point separately. If the event was a mouse event, this
71-
// will hand back an array with one element, which we're fine handling.
72-
const events = Touch.splitEventByTouches(e);
73-
for (let i = 0; i < events.length; i++) {
74-
const event = events[i];
75-
if (captureIdentifier && !Touch.shouldHandleEvent(event)) {
76-
continue;
77-
}
78-
Touch.setClientFromTouch(event);
73+
74+
if (!(captureIdentifier && !Touch.shouldHandleEvent(e))) {
7975
if (thisObject) {
80-
func.call(thisObject, event);
76+
func.call(thisObject, e);
8177
} else {
82-
func(event);
78+
func(e);
8379
}
84-
handled = true;
8580
}
8681
}
8782

8883
const bindData: Data = [];
89-
if (globalThis['PointerEvent'] && name in Touch.TOUCH_MAP) {
84+
if (name in Touch.TOUCH_MAP) {
9085
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
9186
const type = Touch.TOUCH_MAP[name][i];
9287
node.addEventListener(type, wrapFunc, false);
@@ -95,24 +90,6 @@ export function conditionalBind(
9590
} else {
9691
node.addEventListener(name, wrapFunc, false);
9792
bindData.push([node, name, wrapFunc]);
98-
99-
// Add equivalent touch event.
100-
if (name in Touch.TOUCH_MAP) {
101-
const touchWrapFunc = (e: Event) => {
102-
wrapFunc(e);
103-
// Calling preventDefault stops the browser from scrolling/zooming the
104-
// page.
105-
const preventDef = !opt_noPreventDefault;
106-
if (handled && preventDef) {
107-
e.preventDefault();
108-
}
109-
};
110-
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
111-
const type = Touch.TOUCH_MAP[name][i];
112-
node.addEventListener(type, touchWrapFunc, false);
113-
bindData.push([node, type, touchWrapFunc]);
114-
}
115-
}
11693
}
11794
return bindData;
11895
}
@@ -146,7 +123,7 @@ export function bind(
146123
}
147124

148125
const bindData: Data = [];
149-
if (globalThis['PointerEvent'] && name in Touch.TOUCH_MAP) {
126+
if (name in Touch.TOUCH_MAP) {
150127
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
151128
const type = Touch.TOUCH_MAP[name][i];
152129
node.addEventListener(type, wrapFunc, false);
@@ -155,32 +132,6 @@ export function bind(
155132
} else {
156133
node.addEventListener(name, wrapFunc, false);
157134
bindData.push([node, name, wrapFunc]);
158-
159-
// Add equivalent touch event.
160-
if (name in Touch.TOUCH_MAP) {
161-
const touchWrapFunc = (e: Event) => {
162-
// Punt on multitouch events.
163-
if (e instanceof TouchEvent && e.changedTouches &&
164-
e.changedTouches.length === 1) {
165-
// Map the touch event's properties to the event.
166-
const touchPoint = e.changedTouches[0];
167-
// TODO (6311): We are trying to make a touch event look like a mouse
168-
// event, which is not allowed, because it requires adding more
169-
// properties to the event. How do we want to deal with this?
170-
(e as AnyDuringMigration).clientX = touchPoint.clientX;
171-
(e as AnyDuringMigration).clientY = touchPoint.clientY;
172-
}
173-
wrapFunc(e);
174-
175-
// Stop the browser from scrolling/zooming the page.
176-
e.preventDefault();
177-
};
178-
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
179-
const type = Touch.TOUCH_MAP[name][i];
180-
node.addEventListener(type, touchWrapFunc, false);
181-
bindData.push([node, type, touchWrapFunc]);
182-
}
183-
}
184135
}
185136
return bindData;
186137
}

core/bubble.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,10 @@ export class Bubble implements IBubble {
249249

250250
if (!this.workspace_.options.readOnly) {
251251
this.onMouseDownBubbleWrapper = browserEvents.conditionalBind(
252-
this.bubbleBack, 'mousedown', this, this.bubbleMouseDown);
252+
this.bubbleBack, 'pointerdown', this, this.bubbleMouseDown);
253253
if (this.resizeGroup) {
254254
this.onMouseDownResizeWrapper = browserEvents.conditionalBind(
255-
this.resizeGroup, 'mousedown', this, this.resizeMouseDown);
255+
this.resizeGroup, 'pointerdown', this, this.resizeMouseDown);
256256
}
257257
}
258258
this.bubbleGroup.appendChild(content);
@@ -278,11 +278,11 @@ export class Bubble implements IBubble {
278278
}
279279

280280
/**
281-
* Handle a mouse-down on bubble's border.
281+
* Handle a pointerdown on bubble's border.
282282
*
283-
* @param e Mouse down event.
283+
* @param e Pointer down event.
284284
*/
285-
private bubbleMouseDown(e: Event) {
285+
private bubbleMouseDown(e: PointerEvent) {
286286
const gesture = this.workspace_.getGesture(e);
287287
if (gesture) {
288288
gesture.handleBubbleStart(e, this);
@@ -318,11 +318,11 @@ export class Bubble implements IBubble {
318318
// NOP if bubble is not deletable.
319319

320320
/**
321-
* Handle a mouse-down on bubble's resize corner.
321+
* Handle a pointerdown on bubble's resize corner.
322322
*
323-
* @param e Mouse down event.
323+
* @param e Pointer down event.
324324
*/
325-
private resizeMouseDown(e: MouseEvent) {
325+
private resizeMouseDown(e: PointerEvent) {
326326
this.promote();
327327
Bubble.unbindDragEvents();
328328
if (browserEvents.isRightButton(e)) {
@@ -337,20 +337,20 @@ export class Bubble implements IBubble {
337337
this.workspace_.RTL ? -this.width : this.width, this.height));
338338

339339
Bubble.onMouseUpWrapper = browserEvents.conditionalBind(
340-
document, 'mouseup', this, Bubble.bubbleMouseUp);
340+
document, 'pointerup', this, Bubble.bubbleMouseUp);
341341
Bubble.onMouseMoveWrapper = browserEvents.conditionalBind(
342-
document, 'mousemove', this, this.resizeMouseMove);
342+
document, 'pointermove', this, this.resizeMouseMove);
343343
this.workspace_.hideChaff();
344344
// This event has been handled. No need to bubble up to the document.
345345
e.stopPropagation();
346346
}
347347

348348
/**
349-
* Resize this bubble to follow the mouse.
349+
* Resize this bubble to follow the pointer.
350350
*
351-
* @param e Mouse move event.
351+
* @param e Pointer move event.
352352
*/
353-
private resizeMouseMove(e: MouseEvent) {
353+
private resizeMouseMove(e: PointerEvent) {
354354
this.autoLayout = false;
355355
const newXY = this.workspace_.moveDrag(e);
356356
this.setBubbleSize(this.workspace_.RTL ? -newXY.x : newXY.x, newXY.y);
@@ -847,11 +847,11 @@ export class Bubble implements IBubble {
847847
}
848848

849849
/**
850-
* Handle a mouse-up event while dragging a bubble's border or resize handle.
850+
* Handle a pointerup event while dragging a bubble's border or resize handle.
851851
*
852-
* @param _e Mouse up event.
852+
* @param _e Pointer up event.
853853
*/
854-
private static bubbleMouseUp(_e: MouseEvent) {
854+
private static bubbleMouseUp(_e: PointerEvent) {
855855
Touch.clearTouchIdentifier();
856856
Bubble.unbindDragEvents();
857857
}

core/bubble_dragger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class BubbleDragger {
8989
* at the start of the drag, in pixel units.
9090
* @internal
9191
*/
92-
dragBubble(e: Event, currentDragDeltaXY: Coordinate) {
92+
dragBubble(e: PointerEvent, currentDragDeltaXY: Coordinate) {
9393
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
9494
const newLoc = Coordinate.sum(this.startXY_, delta);
9595
this.bubble.moveDuringDrag(this.dragSurface_, newLoc);
@@ -141,12 +141,12 @@ export class BubbleDragger {
141141
/**
142142
* Finish a bubble drag and put the bubble back on the workspace.
143143
*
144-
* @param e The mouseup/touchend event.
144+
* @param e The pointerup event.
145145
* @param currentDragDeltaXY How far the pointer has moved from the position
146146
* at the start of the drag, in pixel units.
147147
* @internal
148148
*/
149-
endBubbleDrag(e: Event, currentDragDeltaXY: Coordinate) {
149+
endBubbleDrag(e: PointerEvent, currentDragDeltaXY: Coordinate) {
150150
// Make sure internal state is fresh.
151151
this.dragBubble(e, currentDragDeltaXY);
152152

core/comment.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,8 @@ export class Comment extends Icon {
149149
body.appendChild(textarea);
150150
this.foreignObject!.appendChild(body);
151151

152-
// Ideally this would be hooked to the focus event for the comment.
153-
// However doing so in Firefox swallows the cursor for unknown reasons.
154-
// So this is hooked to mouseup instead. No big deal.
155152
this.onMouseUpWrapper = browserEvents.conditionalBind(
156-
textarea, 'mouseup', this, this.startEdit, true, true);
153+
textarea, 'focus', this, this.startEdit, true);
157154
// Don't zoom with mousewheel.
158155
this.onWheelWrapper = browserEvents.conditionalBind(
159156
textarea, 'wheel', this, function(e: Event) {
@@ -315,7 +312,7 @@ export class Comment extends Icon {
315312
*
316313
* @param _e Mouse up event.
317314
*/
318-
private startEdit(_e: Event) {
315+
private startEdit(_e: PointerEvent) {
319316
if (this.bubble_?.promote()) {
320317
// Since the act of moving this node within the DOM causes a loss of
321318
// focus, we need to reapply the focus.

core/field.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ export abstract class Field<T = unknown> implements IASTNodeLocationSvg,
361361
if (!clickTarget) throw new Error('A click target has not been set.');
362362
Tooltip.bindMouseEvents(clickTarget);
363363
this.mouseDownWrapper_ = browserEvents.conditionalBind(
364-
clickTarget, 'mousedown', this, this.onMouseDown_);
364+
clickTarget, 'pointerdown', this, this.onMouseDown_);
365365
}
366366

367367
/**
@@ -1076,11 +1076,11 @@ export abstract class Field<T = unknown> implements IASTNodeLocationSvg,
10761076
// NOP
10771077

10781078
/**
1079-
* Handle a mouse down event on a field.
1079+
* Handle a pointerdown event on a field.
10801080
*
1081-
* @param e Mouse down event.
1081+
* @param e Pointer down event.
10821082
*/
1083-
protected onMouseDown_(e: Event) {
1083+
protected onMouseDown_(e: PointerEvent) {
10841084
if (!this.sourceBlock_ || this.sourceBlock_.isDeadOrDying()) {
10851085
return;
10861086
}

0 commit comments

Comments
 (0)