-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle reentrant focus/blur events #1550
Comments
Here is the described reorder change: a94d4b6 |
I believe this is a problem again in phetsims/my-solar-system#157, reentrant focus and blur events are causing focus to be lost. After releasing the 'enter' key on the combo box item in my-solar-system, here are the batched events when the button becomes blurred again: Events before the third have already run and are disposed. |
My thoughts on this were
I believe that means PDOM related events should be run synchronously (with no batching) and run with reentrancy (as they are triggered by the browser). Here is a patch that does this: Subject: [PATCH] Use Checkbox directly, remove superclass, see https://github.com/phetsims/gravity-force-lab-basics/issues/324"
---
Index: js/input/Input.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/Input.ts b/js/input/Input.ts
--- a/js/input/Input.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/Input.ts (date 1681509759691)
@@ -880,6 +880,8 @@
// Additionally, IE had some issues with skipping prevent default, see
// https://github.com/phetsims/scenery/issues/464 for mouse handling.
// WE WILL NOT preventDefault() on keyboard or alternative input events here
+
+ // TODO - document that ALT_TYPE is not currently going through this function.
if ( !( this.passiveEvents === true ) &&
( callback !== this.mouseDown || platform.edge ) &&
batchType !== BatchedDOMEventType.ALT_TYPE ) {
Index: js/input/BrowserEvents.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/BrowserEvents.js b/js/input/BrowserEvents.js
--- a/js/input/BrowserEvents.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/BrowserEvents.js (date 1681508735738)
@@ -8,7 +8,7 @@
import arrayRemove from '../../../phet-core/js/arrayRemove.js';
import platform from '../../../phet-core/js/platform.js';
-import { BatchedDOMEventType, Display, Features, FocusManager, globalKeyStateTracker, PDOMUtils, scenery } from '../imports.js';
+import { BatchedDOMEvent, BatchedDOMEventType, Display, Features, FocusManager, globalKeyStateTracker, PDOMUtils, scenery } from '../imports.js';
// Sometimes we need to add a listener that does absolutely nothing
const noop = () => {};
@@ -337,6 +337,26 @@
}
},
+ /**
+ * Runs an event from the window immediately on all displays. Listeners (and any reentrant events) are all
+ * run synchronously.
+ *
+ * Accessibility related events (that go through the PDOM) in particular should not be batched because
+ * they need to be run with the DOM being at the same state as the trigger.
+ *
+ * @param {Event} domEvent
+ * @param {BatchedDOMEventType} batchType
+ * @param {string} inputCallbackName
+ */
+ runWindowEvent( domEvent, batchType, inputCallbackName ) {
+ for ( let i = 0; i < this.attachedDisplays.length; i++ ) {
+ const display = this.attachedDisplays[ i ];
+ const input = display._input;
+ const batchedEvent = BatchedDOMEvent.pool.create( domEvent, batchType, input[ inputCallbackName ] );
+ batchedEvent.run( input );
+ }
+ },
+
/**
* Listener for window's pointerdown event.
* @private
@@ -738,7 +758,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusIn', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusIn' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -748,7 +768,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusOut', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusOut' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -758,7 +778,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'input', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'input' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -768,7 +788,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'change', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'change' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -778,7 +798,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'click', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'click' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -788,7 +808,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyDown', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyDown' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -798,7 +818,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyUp', true );
+ BrowserEvents.runWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyUp' );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
}
This fixes the problem, and unit and fuzz tests are passing. Also, PDOM related events behaved this way prior to work done ~9/22 (PhET alt input sprint). However, in a meeting today @jonathanolson described the importance of batching. It makes sure that all callbacks for an event are fired in the order of events. Needing to support reentrancy well will also add a lot of complexity. We should look into saving the DOM state we care about so that listeners can run with correct information. Maybe the steps for this would go like
I will be out of office and can't work on this again until 4/24 but I spoke to @jonathanolson and he kindly agreed to work on this as part of my-solar-system. Assigning to him. |
Current patch (significant changes, we pass EventContext through a lot. beneficial, and we actually GET RID of not having events for things, due to EventContext.createSynthetic(), so there is a lot of potential benefit from this patch we may want to include anyway): Subject: [PATCH] Adding activeElement/context to Input, see https://github.com/phetsims/scenery/issues/1550
---
Index: js/input/Input.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/Input.ts b/js/input/Input.ts
--- a/js/input/Input.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/Input.ts (date 1681949983692)
@@ -173,7 +173,7 @@
import Tandem from '../../../tandem/js/Tandem.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import NumberIO from '../../../tandem/js/types/NumberIO.js';
-import { BatchedDOMEvent, BatchedDOMEventCallback, BatchedDOMEventType, BrowserEvents, Display, EventIO, Mouse, Node, PDOMInstance, PDOMPointer, PDOMUtils, Pen, Pointer, scenery, SceneryEvent, SceneryListenerFunction, SupportedEventTypes, TInputListener, Touch, Trail, WindowTouch } from '../imports.js';
+import { BatchedDOMEvent, BatchedDOMEventCallback, BatchedDOMEventType, BrowserEvents, Display, EventContext, EventContextIO, Mouse, Node, PDOMInstance, PDOMPointer, PDOMUtils, Pen, Pointer, scenery, SceneryEvent, SceneryListenerFunction, SupportedEventTypes, TInputListener, Touch, Trail, WindowTouch } from '../imports.js';
import PhetioObject, { PhetioObjectOptions } from '../../../tandem/js/PhetioObject.js';
import IOType from '../../../tandem/js/types/IOType.js';
import ArrayIO from '../../../tandem/js/types/ArrayIO.js';
@@ -302,31 +302,31 @@
// This is a high frequency event that is necessary for reproducible playbacks
private readonly validatePointersAction: PhetioAction;
- private readonly mouseUpAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly mouseDownAction: PhetioAction<[ number, Vector2, MouseEvent ]>;
- private readonly mouseMoveAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly mouseOverAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly mouseOutAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly wheelScrollAction: PhetioAction<[ WheelEvent ]>;
- private readonly touchStartAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly touchEndAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly touchMoveAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly touchCancelAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly penStartAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly penEndAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly penMoveAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly penCancelAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly gotPointerCaptureAction: PhetioAction<[ number, Event ]>;
- private readonly lostPointerCaptureAction: PhetioAction<[ number, Event ]>;
+ private readonly mouseUpAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseDownAction: PhetioAction<[ number, Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseMoveAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseOverAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseOutAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly wheelScrollAction: PhetioAction<[ EventContext<WheelEvent> ]>;
+ private readonly touchStartAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly touchEndAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly touchMoveAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly touchCancelAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly penStartAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly penEndAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly penMoveAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly penCancelAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly gotPointerCaptureAction: PhetioAction<[ number, EventContext ]>;
+ private readonly lostPointerCaptureAction: PhetioAction<[ number, EventContext ]>;
// If accessible
- private readonly focusinAction: PhetioAction<[ FocusEvent ]>;
- private readonly focusoutAction: PhetioAction<[ FocusEvent ]>;
- private readonly clickAction: PhetioAction<[ MouseEvent ]>;
- private readonly inputAction: PhetioAction<[ Event | InputEvent ]>;
- private readonly changeAction: PhetioAction<[ Event ]>;
- private readonly keydownAction: PhetioAction<[ KeyboardEvent ]>;
- private readonly keyupAction: PhetioAction<[ KeyboardEvent ]>;
+ private readonly focusinAction: PhetioAction<[ EventContext<FocusEvent> ]>;
+ private readonly focusoutAction: PhetioAction<[ EventContext<FocusEvent> ]>;
+ private readonly clickAction: PhetioAction<[ EventContext<MouseEvent> ]>;
+ private readonly inputAction: PhetioAction<[ EventContext<Event | InputEvent> ]>;
+ private readonly changeAction: PhetioAction<[ EventContext ]>;
+ private readonly keydownAction: PhetioAction<[ EventContext<KeyboardEvent> ]>;
+ private readonly keyupAction: PhetioAction<[ EventContext<KeyboardEvent> ]>;
public static readonly InputIO = new IOType<Input>( 'InputIO', {
valueType: Input,
@@ -386,7 +386,7 @@
while ( i-- ) {
const pointer = this.pointers[ i ];
if ( pointer.point && pointer !== this.pdomPointer ) {
- this.branchChangeEvents<Event>( pointer, pointer.lastDOMEvent, false );
+ this.branchChangeEvents<Event>( pointer, pointer.lastEventContext || EventContext.createSynthetic(), false );
}
}
}, {
@@ -395,54 +395,54 @@
phetioHighFrequency: true
} );
- this.mouseUpAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseUpAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.id = null;
- this.upEvent<MouseEvent>( mouse, event, point );
+ this.upEvent<MouseEvent>( mouse, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'mouseUpAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a mouse button is released.'
} );
- this.mouseDownAction = new PhetioAction( ( id: number, point: Vector2, event: MouseEvent ) => {
+ this.mouseDownAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.id = id;
- this.downEvent<MouseEvent>( mouse, event, point );
+ this.downEvent<MouseEvent>( mouse, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'mouseDownAction' ),
parameters: [
{ name: 'id', phetioType: NullableIO( NumberIO ) },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a mouse button is pressed.'
} );
- this.mouseMoveAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseMoveAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.move( point );
- this.moveEvent<MouseEvent>( mouse, event );
+ this.moveEvent<MouseEvent>( mouse, context );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'mouseMoveAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse is moved.',
phetioHighFrequency: true
} );
- this.mouseOverAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseOverAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.over( point );
// TODO: how to handle mouse-over (and log it)... are we changing the pointer.point without a branch change?
@@ -451,13 +451,13 @@
tandem: options.tandem.createTandem( 'mouseOverAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse is moved while on the sim.'
} );
- this.mouseOutAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseOutAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.out( point );
// TODO: how to handle mouse-out (and log it)... are we changing the pointer.point without a branch change?
@@ -466,13 +466,15 @@
tandem: options.tandem.createTandem( 'mouseOutAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse moves out of the display.'
} );
- this.wheelScrollAction = new PhetioAction( ( event: WheelEvent ) => {
+ this.wheelScrollAction = new PhetioAction( ( context: EventContext<WheelEvent> ) => {
+ const event = context.domEvent;
+
const mouse = this.ensureMouse( this.pointFromEvent( event ) );
mouse.wheel( event );
@@ -480,40 +482,40 @@
// TODO: Can we set the mouse location based on the wheel event?
if ( mouse.point ) {
const trail = this.rootNode.trailUnderPointer( mouse ) || new Trail( this.rootNode );
- this.dispatchEvent<WheelEvent>( trail, 'wheel', mouse, event, true );
+ this.dispatchEvent<WheelEvent>( trail, 'wheel', mouse, context, true );
}
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'wheelScrollAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse wheel scrolls.',
phetioHighFrequency: true
} );
- this.touchStartAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
- const touch = new Touch( id, point, event );
+ this.touchStartAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
+ const touch = new Touch( id, point, context.domEvent );
this.addPointer( touch );
- this.downEvent<TouchEvent | PointerEvent>( touch, event, point );
+ this.downEvent<TouchEvent | PointerEvent>( touch, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'touchStartAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch begins.'
} );
- this.touchEndAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
+ this.touchEndAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
const touch = this.findPointerById( id ) as Touch | null;
if ( touch ) {
assert && assert( touch instanceof Touch ); // eslint-disable-line no-simple-type-checking-assertions, bad-sim-text
- this.upEvent<TouchEvent | PointerEvent>( touch, event, point );
+ this.upEvent<TouchEvent | PointerEvent>( touch, context, point );
this.removePointer( touch );
}
}, {
@@ -522,18 +524,18 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch ends.'
} );
- this.touchMoveAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
+ this.touchMoveAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
const touch = this.findPointerById( id ) as Touch | null;
if ( touch ) {
assert && assert( touch instanceof Touch ); // eslint-disable-line no-simple-type-checking-assertions, bad-sim-text
touch.move( point );
- this.moveEvent<TouchEvent | PointerEvent>( touch, event );
+ this.moveEvent<TouchEvent | PointerEvent>( touch, context );
}
}, {
phetioPlayback: true,
@@ -541,18 +543,18 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch moves.',
phetioHighFrequency: true
} );
- this.touchCancelAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
+ this.touchCancelAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
const touch = this.findPointerById( id ) as Touch | null;
if ( touch ) {
assert && assert( touch instanceof Touch ); // eslint-disable-line no-simple-type-checking-assertions, bad-sim-text
- this.cancelEvent<TouchEvent | PointerEvent>( touch, event, point );
+ this.cancelEvent<TouchEvent | PointerEvent>( touch, context, point );
this.removePointer( touch );
}
}, {
@@ -561,32 +563,32 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch is canceled.'
} );
- this.penStartAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
- const pen = new Pen( id, point, event );
+ this.penStartAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
+ const pen = new Pen( id, point, context.domEvent );
this.addPointer( pen );
- this.downEvent<PointerEvent>( pen, event, point );
+ this.downEvent<PointerEvent>( pen, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'penStartAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen touches the screen.'
} );
- this.penEndAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
+ this.penEndAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
const pen = this.findPointerById( id ) as Pen | null;
if ( pen ) {
- this.upEvent<PointerEvent>( pen, event, point );
+ this.upEvent<PointerEvent>( pen, context, point );
this.removePointer( pen );
}
}, {
@@ -595,17 +597,17 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen is lifted.'
} );
- this.penMoveAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
+ this.penMoveAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
const pen = this.findPointerById( id ) as Pen | null;
if ( pen ) {
pen.move( point );
- this.moveEvent<PointerEvent>( pen, event );
+ this.moveEvent<PointerEvent>( pen, context );
}
}, {
phetioPlayback: true,
@@ -613,17 +615,17 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen is moved.',
phetioHighFrequency: true
} );
- this.penCancelAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
+ this.penCancelAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
const pen = this.findPointerById( id ) as Pen | null;
if ( pen ) {
- this.cancelEvent<PointerEvent>( pen, event, point );
+ this.cancelEvent<PointerEvent>( pen, context, point );
this.removePointer( pen );
}
}, {
@@ -632,13 +634,13 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen is canceled.'
} );
- this.gotPointerCaptureAction = new PhetioAction( ( id: number, event: Event ) => {
+ this.gotPointerCaptureAction = new PhetioAction( ( id: number, context: EventContext ) => {
const pointer = this.findPointerById( id );
if ( pointer ) {
@@ -649,14 +651,14 @@
tandem: options.tandem.createTandem( 'gotPointerCaptureAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pointer is captured (normally at the start of an interaction)',
phetioHighFrequency: true
} );
- this.lostPointerCaptureAction = new PhetioAction( ( id: number, event: Event ) => {
+ this.lostPointerCaptureAction = new PhetioAction( ( id: number, context: EventContext ) => {
const pointer = this.findPointerById( id );
if ( pointer ) {
@@ -667,15 +669,15 @@
tandem: options.tandem.createTandem( 'lostPointerCaptureAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pointer loses its capture (normally at the end of an interaction)',
phetioHighFrequency: true
} );
- this.focusinAction = new PhetioAction( ( event: FocusEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'focusin' );
+ this.focusinAction = new PhetioAction( ( context: EventContext<FocusEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'focusin' );
if ( !trail ) {
return;
}
@@ -685,25 +687,25 @@
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusin(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusin(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<FocusEvent>( trail, 'focus', event, false );
- this.dispatchPDOMEvent<FocusEvent>( trail, 'focusin', event, true );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'focus', context, false );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'focusin', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'focusinAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the focusin DOM event.'
} );
- this.focusoutAction = new PhetioAction( ( event: FocusEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'focusout' );
+ this.focusoutAction = new PhetioAction( ( context: EventContext<FocusEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'focusout' );
if ( !trail ) {
return;
}
@@ -713,18 +715,18 @@
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<FocusEvent>( trail, 'blur', event, false );
- this.dispatchPDOMEvent<FocusEvent>( trail, 'focusout', event, true );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'blur', context, false );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'focusout', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'focusoutAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the focusout DOM event.'
@@ -732,111 +734,111 @@
// https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event notes that the click action should result
// in a MouseEvent
- this.clickAction = new PhetioAction( ( event: MouseEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'click' );
+ this.clickAction = new PhetioAction( ( context: EventContext<MouseEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'click' );
if ( !trail ) {
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `click(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `click(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<MouseEvent>( trail, 'click', event, true );
+ this.dispatchPDOMEvent<MouseEvent>( trail, 'click', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'clickAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the click DOM event.'
} );
- this.inputAction = new PhetioAction( ( event: Event | InputEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'input' );
+ this.inputAction = new PhetioAction( ( context: EventContext<Event | InputEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'input' );
if ( !trail ) {
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `input(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `input(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<Event | InputEvent>( trail, 'input', event, true );
+ this.dispatchPDOMEvent<Event | InputEvent>( trail, 'input', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'inputAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the input DOM event.'
} );
- this.changeAction = new PhetioAction( ( event: Event ) => {
- const trail = this.getPDOMEventTrail( event, 'change' );
+ this.changeAction = new PhetioAction( ( context: EventContext ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'change' );
if ( !trail ) {
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `change(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `change(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<Event>( trail, 'change', event, true );
+ this.dispatchPDOMEvent<Event>( trail, 'change', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'changeAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the change DOM event.'
} );
- this.keydownAction = new PhetioAction( ( event: KeyboardEvent ) => {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keydown(${Input.debugText( null, event )});` );
+ this.keydownAction = new PhetioAction( ( context: EventContext<KeyboardEvent> ) => {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keydown(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', event, true );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', context, true );
- const trail = this.getPDOMEventTrail( event, 'keydown' );
- trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keydown', event, true );
+ const trail = this.getPDOMEventTrail( context.domEvent, 'keydown' );
+ trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keydown', context, true );
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', event, false );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', context, false );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'keydownAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the keydown DOM event.'
} );
- this.keyupAction = new PhetioAction( ( event: KeyboardEvent ) => {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyup(${Input.debugText( null, event )});` );
+ this.keyupAction = new PhetioAction( ( context: EventContext<KeyboardEvent> ) => {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyup(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', event, true );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', context, true );
- const trail = this.getPDOMEventTrail( event, 'keydown' );
- trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keyup', event, true );
+ const trail = this.getPDOMEventTrail( context.domEvent, 'keydown' );
+ trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keyup', context, true );
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', event, false );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', context, false );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'keyupAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the keyup DOM event.'
@@ -855,20 +857,20 @@
/**
* Called to batch a raw DOM event (which may be immediately fired, depending on the settings). (scenery-internal)
*
- * @param domEvent
+ * @param context
* @param batchType - See BatchedDOMEvent's "enumeration"
* @param callback - Parameter types defined by the batchType. See BatchedDOMEvent for details
* @param triggerImmediate - Certain events can force immediate action, since browsers like Chrome
* only allow certain operations in the callback for a user gesture (e.g. like
* a mouseup to open a window).
*/
- public batchEvent( domEvent: Event, batchType: BatchedDOMEventType, callback: BatchedDOMEventCallback, triggerImmediate: boolean ): void {
+ public batchEvent( context: EventContext, batchType: BatchedDOMEventType, callback: BatchedDOMEventCallback, triggerImmediate: boolean ): void {
sceneryLog && sceneryLog.InputEvent && sceneryLog.InputEvent( 'Input.batchEvent' );
sceneryLog && sceneryLog.InputEvent && sceneryLog.push();
// If our display is not interactive, do not respond to any events (but still prevent default)
if ( this.display.interactive ) {
- this.batchedEvents.push( BatchedDOMEvent.pool.create( domEvent, batchType, callback ) );
+ this.batchedEvents.push( BatchedDOMEvent.pool.create( context, batchType, callback ) );
if ( triggerImmediate || !this.batchDOMEvents ) {
this.fireBatchedEvents();
}
@@ -884,7 +886,7 @@
( callback !== this.mouseDown || platform.edge ) &&
batchType !== BatchedDOMEventType.ALT_TYPE ) {
// We cannot prevent a passive event, so don't try
- domEvent.preventDefault();
+ context.domEvent.preventDefault();
}
sceneryLog && sceneryLog.InputEvent && sceneryLog.pop();
@@ -945,11 +947,6 @@
* Removes all non-Mouse pointers from internal tracking. (scenery-internal)
*/
public removeTemporaryPointers(): void {
- // TODO: Just null this out, instead of creating a fake event?
- const fakeDomEvent = {
- eek: 'This is a fake DOM event created in removeTemporaryPointers(), called from a Scenery exit event. Our attempt to masquerade seems unsuccessful! :('
- } as unknown as Event;
-
for ( let i = this.pointers.length - 1; i >= 0; i-- ) {
const pointer = this.pointers[ i ];
if ( !( pointer instanceof Mouse ) ) {
@@ -957,7 +954,7 @@
// Send exit events. As we can't get a DOM event, we'll send a fake object instead.
const exitTrail = pointer.trail || new Trail( this.rootNode );
- this.exitEvents( pointer, fakeDomEvent, exitTrail, 0, true );
+ this.exitEvents( pointer, EventContext.createSynthetic(), exitTrail, 0, true );
}
}
}
@@ -1107,7 +1104,7 @@
* Steps to dispatch a pdom-related event. Before dispatch, the PDOMPointer is initialized if it
* hasn't been created yet and a userGestureEmitter emits to indicate that a user has begun an interaction.
*/
- private dispatchPDOMEvent<DOMEvent extends Event>( trail: Trail, eventType: SupportedEventTypes, domEvent: DOMEvent, bubbles: boolean ): void {
+ private dispatchPDOMEvent<DOMEvent extends Event>( trail: Trail, eventType: SupportedEventTypes, context: EventContext<DOMEvent>, bubbles: boolean ): void {
this.ensurePDOMPointer().updateTrail( trail );
@@ -1116,6 +1113,8 @@
Display.userGestureEmitter.emit();
}
+ const domEvent = context.domEvent;
+
// This workaround hopefully won't be here forever, see ParallelDOM.setExcludeLabelSiblingFromInput() and https://github.com/phetsims/a11y-research/issues/156
if ( !( domEvent.target && ( domEvent.target as Element ).hasAttribute( PDOMUtils.DATA_EXCLUDE_FROM_INPUT ) ) ) {
@@ -1127,16 +1126,15 @@
trail = new Trail( [] );
}
assert && assert( this.pdomPointer );
- this.dispatchEvent<DOMEvent>( trail, eventType, this.pdomPointer!, domEvent, bubbles );
+ this.dispatchEvent<DOMEvent>( trail, eventType, this.pdomPointer!, context, bubbles );
}
}
- private dispatchGlobalEvent<DOMEvent extends Event>( eventType: SupportedEventTypes, domEvent: DOMEvent, capture: boolean ): void {
-
+ private dispatchGlobalEvent<DOMEvent extends Event>( eventType: SupportedEventTypes, context: EventContext<DOMEvent>, capture: boolean ): void {
this.ensurePDOMPointer();
assert && assert( this.pdomPointer );
const pointer = this.pdomPointer!;
- const inputEvent = new SceneryEvent<DOMEvent>( new Trail(), eventType, pointer, domEvent );
+ const inputEvent = new SceneryEvent<DOMEvent>( new Trail(), eventType, pointer, context );
const recursiveGlobalDispatch = ( node: Node ) => {
if ( !node.isDisposed && node.isVisible() && node.isInputEnabled() ) {
@@ -1212,10 +1210,10 @@
* NOTE: This may also be called from the pointer event handler (pointerDown) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public mouseDown( id: number, point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseDown('${id}', ${Input.debugText( point, event )});` );
+ public mouseDown( id: number, point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseDown('${id}', ${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseDownAction.execute( id, point, event );
+ this.mouseDownAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1225,10 +1223,10 @@
* NOTE: This may also be called from the pointer event handler (pointerUp) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public mouseUp( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseUp(${Input.debugText( point, event )});` );
+ public mouseUp( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseUp(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseUpAction.execute( point, event );
+ this.mouseUpAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1238,40 +1236,40 @@
* NOTE: This may also be called from the pointer event handler (pointerMove) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public mouseMove( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseMove(${Input.debugText( point, event )});` );
+ public mouseMove( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseMove(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseMoveAction.execute( point, event );
+ this.mouseMoveAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Triggers a logical mouseover event (this does NOT correspond to the Scenery event, since this is for the display) (scenery-internal)
*/
- public mouseOver( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOver(${Input.debugText( point, event )});` );
+ public mouseOver( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOver(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseOverAction.execute( point, event );
+ this.mouseOverAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Triggers a logical mouseout event (this does NOT correspond to the Scenery event, since this is for the display) (scenery-internal)
*/
- public mouseOut( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOut(${Input.debugText( point, event )});` );
+ public mouseOut( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOut(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseOutAction.execute( point, event );
+ this.mouseOutAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Triggers a logical mouse-wheel/scroll event. (scenery-internal)
*/
- public wheel( event: WheelEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `wheel(${Input.debugText( null, event )});` );
+ public wheel( context: EventContext<WheelEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `wheel(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.wheelScrollAction.execute( event );
+ this.wheelScrollAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1281,11 +1279,11 @@
* NOTE: This may also be called from the pointer event handler (pointerDown) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchStart( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchStart('${id}',${Input.debugText( point, event )});` );
+ public touchStart( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchStart('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchStartAction.execute( id, point, event );
+ this.touchStartAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1296,11 +1294,11 @@
* NOTE: This may also be called from the pointer event handler (pointerUp) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchEnd( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchEnd('${id}',${Input.debugText( point, event )});` );
+ public touchEnd( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchEnd('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchEndAction.execute( id, point, event );
+ this.touchEndAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1311,10 +1309,10 @@
* NOTE: This may also be called from the pointer event handler (pointerMove) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchMove( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchMove('${id}',${Input.debugText( point, event )});` );
+ public touchMove( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchMove('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchMoveAction.execute( id, point, event );
+ this.touchMoveAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1324,10 +1322,10 @@
* NOTE: This may also be called from the pointer event handler (pointerCancel) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchCancel( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchCancel('${id}',${Input.debugText( point, event )});` );
+ public touchCancel( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchCancel('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchCancelAction.execute( id, point, event );
+ this.touchCancelAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1337,10 +1335,10 @@
* NOTE: This may also be called from the pointer event handler (pointerDown) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penStart( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penStart('${id}',${Input.debugText( point, event )});` );
+ public penStart( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penStart('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penStartAction.execute( id, point, event );
+ this.penStartAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1350,10 +1348,10 @@
* NOTE: This may also be called from the pointer event handler (pointerUp) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penEnd( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penEnd('${id}',${Input.debugText( point, event )});` );
+ public penEnd( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penEnd('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penEndAction.execute( id, point, event );
+ this.penEndAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1363,10 +1361,10 @@
* NOTE: This may also be called from the pointer event handler (pointerMove) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penMove( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penMove('${id}',${Input.debugText( point, event )});` );
+ public penMove( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penMove('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penMoveAction.execute( id, point, event );
+ this.penMoveAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1376,37 +1374,37 @@
* NOTE: This may also be called from the pointer event handler (pointerCancel) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penCancel( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penCancel('${id}',${Input.debugText( point, event )});` );
+ public penCancel( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penCancel('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penCancelAction.execute( id, point, event );
+ this.penCancelAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Handles a pointerdown event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerDown( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerDown( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// In IE for pointer down events, we want to make sure than the next interactions off the page are sent to
// this element (it will bubble). See https://github.com/phetsims/scenery/issues/464 and
// http://news.qooxdoo.org/mouse-capturing.
const target = this.attachToWindow ? document.body : this.display.domElement;
- if ( target.setPointerCapture && event.pointerId ) {
+ if ( target.setPointerCapture && context.domEvent.pointerId ) {
// NOTE: This will error out if run on a playback destination, where a pointer with the given ID does not exist.
- target.setPointerCapture( event.pointerId );
+ target.setPointerCapture( context.domEvent.pointerId );
}
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
// The actual event afterwards
- this.mouseDown( id, point, event );
+ this.mouseDown( id, point, context );
break;
case 'touch':
- this.touchStart( id, point, event );
+ this.touchStart( id, point, context );
break;
case 'pen':
- this.penStart( id, point, event );
+ this.penStart( id, point, context );
break;
default:
if ( assert ) {
@@ -1418,21 +1416,21 @@
/**
* Handles a pointerup event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerUp( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerUp( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// update this outside of the Action executions so that PhET-iO event playback does not override it
- this.upTimeStamp = event.timeStamp;
+ this.upTimeStamp = context.domEvent.timeStamp;
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
- this.mouseUp( point, event );
+ this.mouseUp( point, context );
break;
case 'touch':
- this.touchEnd( id, point, event );
+ this.touchEnd( id, point, context );
break;
case 'pen':
- this.penEnd( id, point, event );
+ this.penEnd( id, point, context );
break;
default:
if ( assert ) {
@@ -1444,7 +1442,7 @@
/**
* Handles a pointercancel event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerCancel( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerCancel( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
@@ -1453,10 +1451,10 @@
}
break;
case 'touch':
- this.touchCancel( id, point, event );
+ this.touchCancel( id, point, context );
break;
case 'pen':
- this.penCancel( id, point, event );
+ this.penCancel( id, point, context );
break;
default:
if ( console.log ) {
@@ -1468,37 +1466,37 @@
/**
* Handles a gotpointercapture event, forwarding it to the proper logical event. (scenery-internal)
*/
- public gotPointerCapture( id: number, type: string, point: Vector2, event: Event ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `gotPointerCapture('${id}',${Input.debugText( null, event )});` );
+ public gotPointerCapture( id: number, type: string, point: Vector2, context: EventContext ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `gotPointerCapture('${id}',${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.gotPointerCaptureAction.execute( id, event );
+ this.gotPointerCaptureAction.execute( id, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Handles a lostpointercapture event, forwarding it to the proper logical event. (scenery-internal)
*/
- public lostPointerCapture( id: number, type: string, point: Vector2, event: Event ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `lostPointerCapture('${id}',${Input.debugText( null, event )});` );
+ public lostPointerCapture( id: number, type: string, point: Vector2, context: EventContext ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `lostPointerCapture('${id}',${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.lostPointerCaptureAction.execute( id, event );
+ this.lostPointerCaptureAction.execute( id, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Handles a pointermove event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerMove( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerMove( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
- this.mouseMove( point, event );
+ this.mouseMove( point, context );
break;
case 'touch':
- this.touchMove( id, point, event );
+ this.touchMove( id, point, context );
break;
case 'pen':
- this.penMove( id, point, event );
+ this.penMove( id, point, context );
break;
default:
if ( console.log ) {
@@ -1510,7 +1508,7 @@
/**
* Handles a pointerover event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerOver( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerOver( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1518,7 +1516,7 @@
/**
* Handles a pointerout event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerOut( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerOut( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1526,7 +1524,7 @@
/**
* Handles a pointerenter event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerEnter( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerEnter( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1534,7 +1532,7 @@
/**
* Handles a pointerleave event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerLeave( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerLeave( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1542,11 +1540,11 @@
/**
* Handles a focusin event, forwarding it to the proper logical event. (scenery-internal)
*/
- public focusIn( event: FocusEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusIn('${Input.debugText( null, event )});` );
+ public focusIn( context: EventContext<FocusEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusIn('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.focusinAction.execute( event );
+ this.focusinAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1554,23 +1552,23 @@
/**
* Handles a focusout event, forwarding it to the proper logical event. (scenery-internal)
*/
- public focusOut( event: FocusEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut('${Input.debugText( null, event )});` );
+ public focusOut( context: EventContext<FocusEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.focusoutAction.execute( event );
+ this.focusoutAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
- * Handles a input event, forwarding it to the proper logical event. (scenery-internal)
+ * Handles an input event, forwarding it to the proper logical event. (scenery-internal)
*/
- public input( event: Event | InputEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `input('${Input.debugText( null, event )});` );
+ public input( context: EventContext<Event | InputEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `input('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.inputAction.execute( event );
+ this.inputAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1578,11 +1576,11 @@
/**
* Handles a change event, forwarding it to the proper logical event. (scenery-internal)
*/
- public change( event: Event ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `change('${Input.debugText( null, event )});` );
+ public change( context: EventContext ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `change('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.changeAction.execute( event );
+ this.changeAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1590,11 +1588,11 @@
/**
* Handles a click event, forwarding it to the proper logical event. (scenery-internal)
*/
- public click( event: MouseEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `click('${Input.debugText( null, event )});` );
+ public click( context: EventContext<MouseEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `click('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.clickAction.execute( event );
+ this.clickAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1602,11 +1600,11 @@
/**
* Handles a keydown event, forwarding it to the proper logical event. (scenery-internal)
*/
- public keyDown( event: KeyboardEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyDown('${Input.debugText( null, event )});` );
+ public keyDown( context: EventContext<KeyboardEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyDown('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.keydownAction.execute( event );
+ this.keydownAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1614,11 +1612,11 @@
/**
* Handles a keyup event, forwarding it to the proper logical event. (scenery-internal)
*/
- public keyUp( event: KeyboardEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyUp('${Input.debugText( null, event )});` );
+ public keyUp( context: EventContext<KeyboardEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyUp('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.keyupAction.execute( event );
+ this.keyupAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1646,28 +1644,27 @@
/**
* Called for each logical "up" event, for any pointer type.
*/
- private upEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent, point: Vector2 ): void {
-
+ private upEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, point: Vector2 ): void {
// if the event target is within the PDOM the AT is sending a fake pointer event to the document - do not
// dispatch this since the PDOM should only handle Input.PDOM_EVENT_TYPES, and all other pointer input should
// go through the Display div. Otherwise, activation will be duplicated when we handle pointer and PDOM events
- if ( this.isTargetUnderPDOM( event.target as HTMLElement ) ) {
+ if ( this.isTargetUnderPDOM( context.domEvent.target as HTMLElement ) ) {
return;
}
- const pointChanged = pointer.up( point, event );
+ const pointChanged = pointer.up( point, context.domEvent );
sceneryLog && sceneryLog.Input && sceneryLog.Input( `upEvent ${pointer.toString()} changed:${pointChanged}` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
// We'll use this trail for the entire dispatch of this event.
- const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, event, pointChanged );
+ const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, context, pointChanged );
- this.dispatchEvent<DOMEvent>( eventTrail, 'up', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( eventTrail, 'up', pointer, context, true );
// touch pointers are transient, so fire exit/out to the trail afterwards
if ( pointer.isTouchLike() ) {
- this.exitEvents<DOMEvent>( pointer, event, eventTrail, 0, true );
+ this.exitEvents<DOMEvent>( pointer, context, eventTrail, 0, true );
}
sceneryLog && sceneryLog.Input && sceneryLog.pop();
@@ -1676,12 +1673,11 @@
/**
* Called for each logical "down" event, for any pointer type.
*/
- private downEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent, point: Vector2 ): void {
-
+ private downEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, point: Vector2 ): void {
// if the event target is within the PDOM the AT is sending a fake pointer event to the document - do not
// dispatch this since the PDOM should only handle Input.PDOM_EVENT_TYPES, and all other pointer input should
// go through the Display div. Otherwise, activation will be duplicated when we handle pointer and PDOM events
- if ( this.isTargetUnderPDOM( event.target as HTMLElement ) ) {
+ if ( this.isTargetUnderPDOM( context.domEvent.target as HTMLElement ) ) {
return;
}
@@ -1691,11 +1687,11 @@
sceneryLog && sceneryLog.Input && sceneryLog.push();
// We'll use this trail for the entire dispatch of this event.
- const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, event, pointChanged );
+ const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, context, pointChanged );
- pointer.down( event );
+ pointer.down( context.domEvent );
- this.dispatchEvent<DOMEvent>( eventTrail, 'down', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( eventTrail, 'down', pointer, context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1703,12 +1699,12 @@
/**
* Called for each logical "move" event, for any pointer type.
*/
- private moveEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent ): void {
+ private moveEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent> ): void {
sceneryLog && sceneryLog.Input && sceneryLog.Input( `moveEvent ${pointer.toString()}` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
// Always treat move events as "point changed"
- this.branchChangeEvents<DOMEvent>( pointer, event, true );
+ this.branchChangeEvents<DOMEvent>( pointer, context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1716,21 +1712,20 @@
/**
* Called for each logical "cancel" event, for any pointer type.
*/
- private cancelEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent, point: Vector2 ): void {
-
+ private cancelEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, point: Vector2 ): void {
const pointChanged = pointer.cancel( point );
sceneryLog && sceneryLog.Input && sceneryLog.Input( `cancelEvent ${pointer.toString()} changed:${pointChanged}` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
// We'll use this trail for the entire dispatch of this event.
- const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, event, pointChanged );
+ const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, context, pointChanged );
- this.dispatchEvent<DOMEvent>( eventTrail, 'cancel', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( eventTrail, 'cancel', pointer, context, true );
// touch pointers are transient, so fire exit/out to the trail afterwards
if ( pointer.isTouchLike() ) {
- this.exitEvents<DOMEvent>( pointer, event, eventTrail, 0, true );
+ this.exitEvents<DOMEvent>( pointer, context, eventTrail, 0, true );
}
sceneryLog && sceneryLog.Input && sceneryLog.pop();
@@ -1743,11 +1738,11 @@
* out/over events, and if flagged a move event.
*
* @param pointer
- * @param event
+ * @param context
* @param sendMove - Whether to send move events
* @returns - The current trail of the pointer
*/
- private branchChangeEvents<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent | null, sendMove: boolean ): Trail {
+ private branchChangeEvents<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, sendMove: boolean ): Trail {
sceneryLog && sceneryLog.InputEvent && sceneryLog.InputEvent(
`branchChangeEvents: ${pointer.toString()} sendMove:${sendMove}` );
sceneryLog && sceneryLog.InputEvent && sceneryLog.push();
@@ -1769,12 +1764,12 @@
// event order matches http://www.w3.org/TR/DOM-Level-3-Events/#events-mouseevent-event-order
if ( sendMove ) {
- this.dispatchEvent<DOMEvent>( trail, 'move', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( trail, 'move', pointer, context, true );
}
// We want to approximately mimic http://www.w3.org/TR/DOM-Level-3-Events/#events-mouseevent-event-order
- this.exitEvents<DOMEvent>( pointer, event, oldInputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
- this.enterEvents<DOMEvent>( pointer, event, inputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
+ this.exitEvents<DOMEvent>( pointer, context, oldInputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
+ this.enterEvents<DOMEvent>( pointer, context, inputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
pointer.trail = trail;
pointer.inputEnabledTrail = inputEnabledTrail;
@@ -1799,13 +1794,13 @@
* for this node and all "descendant" nodes in the relevant trail.
* @param lastNodeChanged - If the last node didn't change, we won't sent an over event.
*/
- private enterEvents<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent | null, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
+ private enterEvents<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
if ( lastNodeChanged ) {
- this.dispatchEvent<DOMEvent>( trail, 'over', pointer, event, true, true );
+ this.dispatchEvent<DOMEvent>( trail, 'over', pointer, context, true, true );
}
for ( let i = branchIndex; i < trail.length; i++ ) {
- this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'enter', pointer, event, false );
+ this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'enter', pointer, context, false );
}
}
@@ -1826,13 +1821,13 @@
* for this node and all "descendant" nodes in the relevant trail.
* @param lastNodeChanged - If the last node didn't change, we won't sent an out event.
*/
- private exitEvents<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent | null, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
+ private exitEvents<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
for ( let i = trail.length - 1; i >= branchIndex; i-- ) {
- this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'exit', pointer, event, false, true );
+ this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'exit', pointer, context, false, true );
}
if ( lastNodeChanged ) {
- this.dispatchEvent<DOMEvent>( trail, 'out', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( trail, 'out', pointer, context, true );
}
}
@@ -1842,11 +1837,11 @@
* @param trail
* @param type
* @param pointer
- * @param event
+ * @param context
* @param bubbles - If bubbles is false, the event is only dispatched to the leaf node of the trail.
* @param fireOnInputDisabled - Whether to fire this event even if nodes have inputEnabled:false
*/
- private dispatchEvent<DOMEvent extends Event>( trail: Trail, type: SupportedEventTypes, pointer: Pointer, event: DOMEvent | null, bubbles: boolean, fireOnInputDisabled = false ): void {
+ private dispatchEvent<DOMEvent extends Event>( trail: Trail, type: SupportedEventTypes, pointer: Pointer, context: EventContext<DOMEvent>, bubbles: boolean, fireOnInputDisabled = false ): void {
sceneryLog && sceneryLog.EventDispatch && sceneryLog.EventDispatch(
`${type} trail:${trail.toString()} pointer:${pointer.toString()} at ${pointer.point ? pointer.point.toString() : 'null'}` );
sceneryLog && sceneryLog.EventDispatch && sceneryLog.push();
@@ -1856,7 +1851,7 @@
sceneryLog && sceneryLog.EventPath && sceneryLog.EventPath( `${type} ${trail.toPathString()}` );
// NOTE: event is not immutable, as its currentTarget changes
- const inputEvent = new SceneryEvent<DOMEvent>( trail, type, pointer, event );
+ const inputEvent = new SceneryEvent<DOMEvent>( trail, type, pointer, context );
// first run through the pointer's listeners to see if one of them will handle the event
this.dispatchToListeners<DOMEvent>( pointer, pointer.getListeners(), type, inputEvent );
Index: js/imports.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/imports.ts b/js/imports.ts
--- a/js/imports.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/imports.ts (date 1681944244538)
@@ -203,6 +203,7 @@
export { default as Pen } from './input/Pen.js';
export { default as PDOMPointer } from './input/PDOMPointer.js';
+export { default as EventContext, EventContextIO } from './input/EventContext.js';
export { default as SceneryEvent } from './input/SceneryEvent.js';
export { default as Input } from './input/Input.js';
Index: js/input/BrowserEvents.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/BrowserEvents.js b/js/input/BrowserEvents.js
--- a/js/input/BrowserEvents.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/BrowserEvents.js (date 1681942929409)
@@ -8,7 +8,7 @@
import arrayRemove from '../../../phet-core/js/arrayRemove.js';
import platform from '../../../phet-core/js/platform.js';
-import { BatchedDOMEventType, Display, Features, FocusManager, globalKeyStateTracker, PDOMUtils, scenery } from '../imports.js';
+import { BatchedDOMEventType, Display, EventContext, Features, FocusManager, globalKeyStateTracker, PDOMUtils, scenery } from '../imports.js';
// Sometimes we need to add a listener that does absolutely nothing
const noop = () => {};
@@ -318,7 +318,7 @@
* Sets an event from the window to be batched on all of the displays.
* @private
*
- * @param {Event} domEvent
+ * @param {EventContext} eventContext
* @param {BatchedDOMEventType} batchType - TODO: turn to full enumeration?
* @param {string} inputCallbackName - e.g. 'mouseDown', will trigger Input.mouseDown
* @param {boolean} triggerImmediate - Whether this will be force-executed now, causing all batched events to fire.
@@ -326,14 +326,14 @@
* necessary for certain security-sensitive actions (like triggering
* full-screen).
*/
- batchWindowEvent( domEvent, batchType, inputCallbackName, triggerImmediate ) {
+ batchWindowEvent( eventContext, batchType, inputCallbackName, triggerImmediate ) {
// NOTE: For now, we don't check whether the event is actually within the display's boundingClientRect. Most
// displays will want to receive events outside of their bounds (especially for checking drags and mouse-ups
// outside of their bounds).
for ( let i = 0; i < this.attachedDisplays.length; i++ ) {
const display = this.attachedDisplays[ i ];
const input = display._input;
- input.batchEvent( domEvent, batchType, input[ inputCallbackName ], triggerImmediate );
+ input.batchEvent( eventContext, batchType, input[ inputCallbackName ], triggerImmediate );
}
},
@@ -347,12 +347,15 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'pointerdown' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
if ( domEvent.pointerType === 'mouse' ) {
Display.userGestureEmitter.emit();
}
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerDown', false );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.POINTER_TYPE, 'pointerDown', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -367,10 +370,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'pointerup' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerUp', true );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.POINTER_TYPE, 'pointerUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -386,7 +392,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -402,7 +408,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerOver', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerOver', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -418,7 +424,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerOut', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerOut', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -434,7 +440,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerCancel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerCancel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -450,7 +456,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'gotPointerCapture', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'gotPointerCapture', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -466,7 +472,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'lostPointerCapture', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'lostPointerCapture', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -482,7 +488,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerDown', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerDown', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -498,7 +504,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerUp', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -514,7 +520,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -530,7 +536,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOver', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOver', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -546,7 +552,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOut', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOut', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -562,7 +568,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerCancel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerCancel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -578,7 +584,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchStart', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.TOUCH_TYPE, 'touchStart', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -593,10 +599,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'touchend' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchEnd', true );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.TOUCH_TYPE, 'touchEnd', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -612,7 +621,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.TOUCH_TYPE, 'touchMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -628,7 +637,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchCancel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.TOUCH_TYPE, 'touchCancel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -643,10 +652,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'mousedown' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseDown', false );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.MOUSE_TYPE, 'mouseDown', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -661,10 +673,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'mouseup' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseUp', true );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.MOUSE_TYPE, 'mouseUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -680,7 +695,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MOUSE_TYPE, 'mouseMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -696,7 +711,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseOver', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MOUSE_TYPE, 'mouseOver', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -712,7 +727,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseOut', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MOUSE_TYPE, 'mouseOut', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -728,7 +743,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.WHEEL_TYPE, 'wheel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.WHEEL_TYPE, 'wheel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -738,7 +753,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusIn', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'focusIn', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -748,7 +763,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusOut', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'focusOut', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -758,7 +773,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'input', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'input', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -768,7 +783,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'change', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'change', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -778,7 +793,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'click', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'click', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -788,7 +803,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyDown', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'keyDown', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -798,7 +813,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyUp', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'keyUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
}
Index: js/input/SceneryEvent.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/SceneryEvent.ts b/js/input/SceneryEvent.ts
--- a/js/input/SceneryEvent.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/SceneryEvent.ts (date 1681950379327)
@@ -16,7 +16,7 @@
import IOType from '../../../tandem/js/types/IOType.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import StringIO from '../../../tandem/js/types/StringIO.js';
-import { Mouse, Node, PDOMPointer, Pointer, scenery, Trail } from '../imports.js';
+import { EventContext, Mouse, Node, PDOMPointer, Pointer, scenery, Trail } from '../imports.js';
import EventIO from './EventIO.js';
// "out" here ensures that SceneryListenerFunctions don't specify a wider type arguments for the event, see https://github.com/phetsims/scenery/issues/1483
@@ -40,6 +40,12 @@
// Raw DOM InputEvent (TouchEvent, PointerEvent, MouseEvent,...)
public readonly domEvent: DOMEvent | null;
+ // Assorted environment information when the event was fired
+ public readonly context: EventContext;
+
+ // The document.activeElement when the event was fired
+ public readonly activeElement: Element | null;
+
// Whatever node you attached the listener to, or null when firing events on a Pointer
public currentTarget: Node | null;
@@ -54,9 +60,9 @@
* @param trail - The trail to the node picked/hit by this input event.
* @param type - Type of the event, e.g. 'string'
* @param pointer - The pointer that triggered this event
- * @param domEvent - The original DOM Event that caused this SceneryEvent to fire.
+ * @param context - The original DOM EventContext that caused this SceneryEvent to fire.
*/
- public constructor( trail: Trail, type: string, pointer: Pointer, domEvent: DOMEvent | null ) {
+ public constructor( trail: Trail, type: string, pointer: Pointer, context: EventContext<DOMEvent> ) {
// TODO: add domEvent type assertion -- will browsers support this?
this.handled = false;
@@ -64,17 +70,17 @@
this.trail = trail;
this.type = type;
this.pointer = pointer;
- this.domEvent = domEvent;
+ this.context = context;
+ this.domEvent = context.domEvent;
+ this.activeElement = context.activeElement;
this.currentTarget = null;
this.target = trail.lastNode();
// TODO: don't require check on domEvent (seems sometimes this is passed as null as a hack?)
- this.isPrimary = !( pointer instanceof Mouse ) || !domEvent || ( domEvent as unknown as MouseEvent ).button === 0;
+ this.isPrimary = !( pointer instanceof Mouse ) || !this.domEvent || ( this.domEvent as unknown as MouseEvent ).button === 0;
// Store the last-used non-null DOM event for future use if required.
- if ( domEvent ) {
- pointer.lastDOMEvent = domEvent;
- }
+ pointer.lastEventContext = context;
}
/**
Index: js/input/InputFuzzer.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/InputFuzzer.js b/js/input/InputFuzzer.js
--- a/js/input/InputFuzzer.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/InputFuzzer.js (date 1681943411930)
@@ -8,7 +8,7 @@
import Random from '../../../dot/js/Random.js';
import Vector2 from '../../../dot/js/Vector2.js';
-import { scenery } from '../imports.js';
+import { EventContext, scenery } from '../imports.js';
class InputFuzzer {
/**
@@ -211,7 +211,7 @@
const event = this.createTouchEvent( 'touchstart', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchStart( touch.id, touch.position, event );
+ this.display._input.touchStart( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -226,7 +226,7 @@
const event = this.createTouchEvent( 'touchmove', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchMove( touch.id, touch.position, event );
+ this.display._input.touchMove( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -239,7 +239,7 @@
const event = this.createTouchEvent( 'touchend', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchEnd( touch.id, touch.position, event );
+ this.display._input.touchEnd( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -252,7 +252,7 @@
const event = this.createTouchEvent( 'touchcancel', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchCancel( touch.id, touch.position, event );
+ this.display._input.touchCancel( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -272,11 +272,11 @@
this.display._input.validatePointers();
if ( this.isMouseDown ) {
- this.display._input.mouseUp( this.mousePosition, domEvent );
+ this.display._input.mouseUp( this.mousePosition, new EventContext( domEvent ) );
this.isMouseDown = false;
}
else {
- this.display._input.mouseDown( null, this.mousePosition, domEvent );
+ this.display._input.mouseDown( null, this.mousePosition, new EventContext( domEvent ) );
this.isMouseDown = true;
}
}
@@ -299,7 +299,7 @@
null );
this.display._input.validatePointers();
- this.display._input.mouseMove( this.mousePosition, domEvent );
+ this.display._input.mouseMove( this.mousePosition, new EventContext( domEvent ) );
}
}
Index: js/input/Pointer.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/Pointer.ts b/js/input/Pointer.ts
--- a/js/input/Pointer.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/Pointer.ts (date 1681948843656)
@@ -30,7 +30,7 @@
import IOType from '../../../tandem/js/types/IOType.js';
import StringIO from '../../../tandem/js/types/StringIO.js';
import TAttachableInputListener from './TAttachableInputListener.js';
-import { scenery, SceneryEvent, TInputListener, Trail } from '../imports.js';
+import { EventContext, scenery, SceneryEvent, TInputListener, Trail } from '../imports.js';
export class Intent extends EnumerationValue {
// listener attached to the pointer will be used for dragging
@@ -88,7 +88,7 @@
// (scenery-internal) - Recorded and exposed so that it can be provided to events when there
// is no "immediate" DOM event (e.g. when a node moves UNDER a pointer and triggers a touch-snag).
- public lastDOMEvent: Event | null;
+ public lastEventContext: EventContext | null;
// A Pointer can be assigned an intent when a listener is attached to initiate or prevent
// certain behavior for the life of the listener. Other listeners can observe the Intents on the Pointer and
@@ -136,7 +136,7 @@
this._listeners = [];
this._attachedListener = null;
this._cursor = null;
- this.lastDOMEvent = null;
+ this.lastEventContext = null;
this._intents = [];
this._pointerCaptured = false;
this._listenerForDragReserve = null;
Index: js/listeners/ListenerTestUtils.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/listeners/ListenerTestUtils.js b/js/listeners/ListenerTestUtils.js
--- a/js/listeners/ListenerTestUtils.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/listeners/ListenerTestUtils.js (date 1681943352378)
@@ -8,6 +8,7 @@
import Vector2 from '../../../dot/js/Vector2.js';
import Display from '../display/Display.js';
+import { EventContext } from '../imports.js';
import Node from '../nodes/Node.js';
import Rectangle from '../nodes/Rectangle.js';
@@ -32,7 +33,7 @@
null );
display._input.validatePointers();
- display._input.mouseDown( null, new Vector2( x, y ), domEvent );
+ display._input.mouseDown( null, new Vector2( x, y ), new EventContext( domEvent ) );
},
/**
@@ -54,7 +55,7 @@
null );
display._input.validatePointers();
- display._input.mouseUp( new Vector2( x, y ), domEvent );
+ display._input.mouseUp( new Vector2( x, y ), new EventContext( domEvent ) );
},
/**
@@ -77,7 +78,7 @@
display._input.validatePointers();
- display._input.mouseMove( new Vector2( x, y ), domEvent );
+ display._input.mouseMove( new Vector2( x, y ), new EventContext( domEvent ) );
},
/**
Index: js/input/EventContext.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/EventContext.ts b/js/input/EventContext.ts
new file mode 100644
--- /dev/null (date 1681948917985)
+++ b/js/input/EventContext.ts (date 1681948917985)
@@ -0,0 +1,53 @@
+// Copyright 2023, University of Colorado Boulder
+
+/**
+ * A collection of information about an event and the environment when it was fired
+ *
+ * @author Jonathan Olson <[email protected]>
+ */
+
+import IOType from '../../../tandem/js/types/IOType.js';
+import { scenery, EventIO, Input } from '../imports.js';
+
+export default class EventContext<out DOMEvent extends Event = Event> {
+
+ // Raw DOM InputEvent (TouchEvent, PointerEvent, MouseEvent,...)
+ public readonly domEvent: DOMEvent;
+
+ // The document.activeElement when the event was fired
+ public readonly activeElement: Element | null;
+
+ public constructor( domEvent: DOMEvent ) {
+ this.domEvent = domEvent;
+ this.activeElement = document.activeElement;
+ }
+
+ public static createSynthetic(): EventContext {
+ return new EventContext( new window.Event( 'synthetic' ) );
+ }
+}
+
+export const EventContextIO = new IOType( 'EventContextIO', {
+ valueType: EventContext,
+ documentation: 'A DOM event and its context',
+ toStateObject: eventContext => {
+ return {
+ domEvent: Input.serializeDomEvent( eventContext.domEvent )
+
+ // Ignores the activeElement, since we don't have a good way of serializing that at this point?
+ };
+ },
+ fromStateObject: stateObject => {
+ return new EventContext( Input.deserializeDomEvent( stateObject.domEvent ) );
+ },
+
+ // This should remain the same as Input.domEventPropertiesToSerialize (local var). Each key can be null depending on
+ // what Event interface is being serialized (which depends on what DOM Event the instance is).
+ stateSchema: () => ( {
+ domEvent: EventIO
+
+ // Ignores the activeElement, since we don't have a good way of serializing that at this point?
+ } )
+} );
+
+scenery.register( 'EventContext', EventContext );
Index: js/input/BatchedDOMEvent.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/BatchedDOMEvent.ts b/js/input/BatchedDOMEvent.ts
--- a/js/input/BatchedDOMEvent.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/BatchedDOMEvent.ts (date 1681950128492)
@@ -11,7 +11,7 @@
import EnumerationValue from '../../../phet-core/js/EnumerationValue.js';
import Pool, { TPoolable } from '../../../phet-core/js/Pool.js';
import IntentionalAny from '../../../phet-core/js/types/IntentionalAny.js';
-import { Input, scenery } from '../imports.js';
+import { EventContext, Input, scenery } from '../imports.js';
export type BatchedDOMEventCallback = ( ...args: IntentionalAny[] ) => void;
@@ -30,19 +30,19 @@
export default class BatchedDOMEvent implements TPoolable {
- private domEvent!: Event | null;
+ private eventContext!: EventContext | null;
private type!: BatchedDOMEventType | null;
private callback!: BatchedDOMEventCallback | null;
- public constructor( domEvent: Event, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ) {
- this.initialize( domEvent, type, callback );
+ public constructor( eventContext: EventContext, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ) {
+ this.initialize( eventContext, type, callback );
}
- public initialize( domEvent: Event, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ): this {
+ public initialize( eventContext: EventContext, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ): this {
// called multiple times due to pooling, this should be re-entrant
- assert && assert( domEvent, 'for some reason, there is no DOM event?' );
+ assert && assert( eventContext.domEvent, 'for some reason, there is no DOM event?' );
- this.domEvent = domEvent;
+ this.eventContext = eventContext;
this.type = type;
this.callback = callback;
@@ -53,7 +53,6 @@
sceneryLog && sceneryLog.InputEvent && sceneryLog.InputEvent( 'Running batched event' );
sceneryLog && sceneryLog.InputEvent && sceneryLog.push();
- const domEvent = this.domEvent!;
const callback = this.callback!;
// process whether anything under the pointers changed before running additional input events
@@ -61,33 +60,37 @@
//OHTWO TODO: switch?
if ( this.type === BatchedDOMEventType.POINTER_TYPE ) {
- const pointerEvent = domEvent as PointerEvent;
- callback.call( input, pointerEvent.pointerId, pointerEvent.pointerType, input.pointFromEvent( pointerEvent ), pointerEvent );
+ const context = this.eventContext as EventContext<PointerEvent>;
+ const pointerEvent = context.domEvent;
+ callback.call( input, pointerEvent.pointerId, pointerEvent.pointerType, input.pointFromEvent( pointerEvent ), context );
}
else if ( this.type === BatchedDOMEventType.MS_POINTER_TYPE ) {
- const pointerEvent = domEvent as PointerEvent;
- callback.call( input, pointerEvent.pointerId, Input.msPointerType( pointerEvent ), input.pointFromEvent( pointerEvent ), pointerEvent );
+ const context = this.eventContext as EventContext<PointerEvent>;
+ const pointerEvent = context.domEvent;
+ callback.call( input, pointerEvent.pointerId, Input.msPointerType( pointerEvent ), input.pointFromEvent( pointerEvent ), context );
}
else if ( this.type === BatchedDOMEventType.TOUCH_TYPE ) {
- const touchEvent = domEvent as TouchEvent;
+ const context = this.eventContext as EventContext<TouchEvent>;
+ const touchEvent = context.domEvent;
for ( let i = 0; i < touchEvent.changedTouches.length; i++ ) {
// according to spec (http://www.w3.org/TR/touch-events/), this is not an Array, but a TouchList
const touch = touchEvent.changedTouches.item( i )!;
- callback.call( input, touch.identifier, input.pointFromEvent( touch ), touchEvent );
+ callback.call( input, touch.identifier, input.pointFromEvent( touch ), context );
}
}
else if ( this.type === BatchedDOMEventType.MOUSE_TYPE ) {
- const mouseEvent = domEvent as MouseEvent;
+ const context = this.eventContext as EventContext<MouseEvent>;
+ const point = input.pointFromEvent( context.domEvent );
if ( callback === input.mouseDown ) {
- callback.call( input, null, input.pointFromEvent( mouseEvent ), mouseEvent );
+ callback.call( input, null, point, context );
}
else {
- callback.call( input, input.pointFromEvent( mouseEvent ), mouseEvent );
+ callback.call( input, point, context );
}
}
else if ( this.type === BatchedDOMEventType.WHEEL_TYPE || this.type === BatchedDOMEventType.ALT_TYPE ) {
- callback.call( input, domEvent );
+ callback.call( input, this.eventContext );
}
else {
throw new Error( `bad type value: ${this.type}` );
@@ -101,7 +104,7 @@
*/
public dispose(): void {
// clear our references
- this.domEvent = null;
+ this.eventContext = null;
this.callback = null;
this.freeToPool();
}
Index: js/input/DownUpListener.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/input/DownUpListener.js b/js/input/DownUpListener.js
--- a/js/input/DownUpListener.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/input/DownUpListener.js (date 1681948864709)
@@ -9,7 +9,7 @@
import deprecationWarning from '../../../phet-core/js/deprecationWarning.js';
import merge from '../../../phet-core/js/merge.js';
import PhetioObject from '../../../tandem/js/PhetioObject.js';
-import { Mouse, scenery, SceneryEvent, Trail } from '../imports.js';
+import { EventContext, Mouse, scenery, SceneryEvent, Trail } from '../imports.js';
/**
* @deprecated - use PressListener instead
@@ -193,9 +193,11 @@
this.interrupted = true;
+ const context = EventContext.createSynthetic();
+
// We create a synthetic event here, as there is no available event here.
// Empty trail, so that it for-sure isn't under our downTrail (guaranteeing that isInside will be false).
- const syntheticEvent = new SceneryEvent( new Trail(), 'synthetic', this.pointer, null );
+ const syntheticEvent = new SceneryEvent( new Trail(), 'synthetic', this.pointer, context );
syntheticEvent.currentTarget = this.downCurrentTarget;
this.buttonUp( syntheticEvent );
Index: js/listeners/SwipeListener.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/listeners/SwipeListener.js b/js/listeners/SwipeListener.js
--- a/js/listeners/SwipeListener.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/js/listeners/SwipeListener.js (date 1681950466444)
@@ -162,8 +162,8 @@
// send a click event to the active element
const pdomRoot = document.getElementsByClassName( 'a11y-pdom-root' )[ 0 ];
- if ( pdomRoot && pdomRoot.contains( document.activeElement ) ) {
- document.activeElement.click();
+ if ( pdomRoot && pdomRoot.contains( event.activeElement ) ) {
+ event.activeElement.click();
}
}
} However, having the activeElement for any event doesn't seem as helpful here. FocusManager.pdomFocusProperty seems to be getting hit twice for each change, so something weird is going on (it shouldn't change, or at least we should use something like useDeepEquality or comparators so that it doesn't fire multiple times). Refocusing elements seems to cause infinite loops (since that chains more events to process). Normal ComboBoxes seem to "unfocus" and then have the button focused, e.g. if I add phet.scenery.FocusManager.pdomFocusProperty.lazyLink( value => console.log( value?.trail.toPathString() ) ); in the console, Density's comboBox (with
However, in MSS's case, it seems to select actual list items afterward:
So in this case, it seems more likely that it's the focusing of the listitemnodes (related target trails?) that then takes away the focus from the button, AND then gets cleared (since we hide the combo box list box). @jessegreenberg it would be good to discuss this to look into it, as (a) my patch might be beneficial long-term, and (b) it seems like a potentially independent issue here. |
Also, if we ever want to store the state of ANYTHING else at the point where input events fire, we should keep my patch! |
@jonathanolson and I met today and made good progress, here is the progress from today. Subject: [PATCH] Use Checkbox directly, remove superclass, see https://github.com/phetsims/gravity-force-lab-basics/issues/324"
---
Index: scenery/js/input/BatchedDOMEvent.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/BatchedDOMEvent.ts b/scenery/js/input/BatchedDOMEvent.ts
--- a/scenery/js/input/BatchedDOMEvent.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/BatchedDOMEvent.ts (date 1682524998235)
@@ -11,7 +11,7 @@
import EnumerationValue from '../../../phet-core/js/EnumerationValue.js';
import Pool, { TPoolable } from '../../../phet-core/js/Pool.js';
import IntentionalAny from '../../../phet-core/js/types/IntentionalAny.js';
-import { Input, scenery } from '../imports.js';
+import { EventContext, Input, scenery } from '../imports.js';
export type BatchedDOMEventCallback = ( ...args: IntentionalAny[] ) => void;
@@ -30,19 +30,19 @@
export default class BatchedDOMEvent implements TPoolable {
- private domEvent!: Event | null;
+ private eventContext!: EventContext | null;
private type!: BatchedDOMEventType | null;
private callback!: BatchedDOMEventCallback | null;
- public constructor( domEvent: Event, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ) {
- this.initialize( domEvent, type, callback );
+ public constructor( eventContext: EventContext, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ) {
+ this.initialize( eventContext, type, callback );
}
- public initialize( domEvent: Event, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ): this {
+ public initialize( eventContext: EventContext, type: BatchedDOMEventType, callback: BatchedDOMEventCallback ): this {
// called multiple times due to pooling, this should be re-entrant
- assert && assert( domEvent, 'for some reason, there is no DOM event?' );
+ assert && assert( eventContext.domEvent, 'for some reason, there is no DOM event?' );
- this.domEvent = domEvent;
+ this.eventContext = eventContext;
this.type = type;
this.callback = callback;
@@ -53,7 +53,6 @@
sceneryLog && sceneryLog.InputEvent && sceneryLog.InputEvent( 'Running batched event' );
sceneryLog && sceneryLog.InputEvent && sceneryLog.push();
- const domEvent = this.domEvent!;
const callback = this.callback!;
// process whether anything under the pointers changed before running additional input events
@@ -61,33 +60,37 @@
//OHTWO TODO: switch?
if ( this.type === BatchedDOMEventType.POINTER_TYPE ) {
- const pointerEvent = domEvent as PointerEvent;
- callback.call( input, pointerEvent.pointerId, pointerEvent.pointerType, input.pointFromEvent( pointerEvent ), pointerEvent );
+ const context = this.eventContext as EventContext<PointerEvent>;
+ const pointerEvent = context.domEvent;
+ callback.call( input, pointerEvent.pointerId, pointerEvent.pointerType, input.pointFromEvent( pointerEvent ), context );
}
else if ( this.type === BatchedDOMEventType.MS_POINTER_TYPE ) {
- const pointerEvent = domEvent as PointerEvent;
- callback.call( input, pointerEvent.pointerId, Input.msPointerType( pointerEvent ), input.pointFromEvent( pointerEvent ), pointerEvent );
+ const context = this.eventContext as EventContext<PointerEvent>;
+ const pointerEvent = context.domEvent;
+ callback.call( input, pointerEvent.pointerId, Input.msPointerType( pointerEvent ), input.pointFromEvent( pointerEvent ), context );
}
else if ( this.type === BatchedDOMEventType.TOUCH_TYPE ) {
- const touchEvent = domEvent as TouchEvent;
+ const context = this.eventContext as EventContext<TouchEvent>;
+ const touchEvent = context.domEvent;
for ( let i = 0; i < touchEvent.changedTouches.length; i++ ) {
// according to spec (http://www.w3.org/TR/touch-events/), this is not an Array, but a TouchList
const touch = touchEvent.changedTouches.item( i )!;
- callback.call( input, touch.identifier, input.pointFromEvent( touch ), touchEvent );
+ callback.call( input, touch.identifier, input.pointFromEvent( touch ), context );
}
}
else if ( this.type === BatchedDOMEventType.MOUSE_TYPE ) {
- const mouseEvent = domEvent as MouseEvent;
+ const context = this.eventContext as EventContext<MouseEvent>;
+ const point = input.pointFromEvent( context.domEvent );
if ( callback === input.mouseDown ) {
- callback.call( input, null, input.pointFromEvent( mouseEvent ), mouseEvent );
+ callback.call( input, null, point, context );
}
else {
- callback.call( input, input.pointFromEvent( mouseEvent ), mouseEvent );
+ callback.call( input, point, context );
}
}
else if ( this.type === BatchedDOMEventType.WHEEL_TYPE || this.type === BatchedDOMEventType.ALT_TYPE ) {
- callback.call( input, domEvent );
+ callback.call( input, this.eventContext );
}
else {
throw new Error( `bad type value: ${this.type}` );
@@ -101,7 +104,7 @@
*/
public dispose(): void {
// clear our references
- this.domEvent = null;
+ this.eventContext = null;
this.callback = null;
this.freeToPool();
}
Index: scenery/js/input/SceneryEvent.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/SceneryEvent.ts b/scenery/js/input/SceneryEvent.ts
--- a/scenery/js/input/SceneryEvent.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/SceneryEvent.ts (date 1682524998379)
@@ -16,7 +16,7 @@
import IOType from '../../../tandem/js/types/IOType.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import StringIO from '../../../tandem/js/types/StringIO.js';
-import { Mouse, Node, PDOMPointer, Pointer, scenery, Trail } from '../imports.js';
+import { EventContext, Mouse, Node, PDOMPointer, Pointer, scenery, Trail } from '../imports.js';
import EventIO from './EventIO.js';
// "out" here ensures that SceneryListenerFunctions don't specify a wider type arguments for the event, see https://github.com/phetsims/scenery/issues/1483
@@ -40,6 +40,12 @@
// Raw DOM InputEvent (TouchEvent, PointerEvent, MouseEvent,...)
public readonly domEvent: DOMEvent | null;
+ // Assorted environment information when the event was fired
+ public readonly context: EventContext;
+
+ // The document.activeElement when the event was fired
+ public readonly activeElement: Element | null;
+
// Whatever node you attached the listener to, or null when firing events on a Pointer
public currentTarget: Node | null;
@@ -54,9 +60,9 @@
* @param trail - The trail to the node picked/hit by this input event.
* @param type - Type of the event, e.g. 'string'
* @param pointer - The pointer that triggered this event
- * @param domEvent - The original DOM Event that caused this SceneryEvent to fire.
+ * @param context - The original DOM EventContext that caused this SceneryEvent to fire.
*/
- public constructor( trail: Trail, type: string, pointer: Pointer, domEvent: DOMEvent | null ) {
+ public constructor( trail: Trail, type: string, pointer: Pointer, context: EventContext<DOMEvent> ) {
// TODO: add domEvent type assertion -- will browsers support this?
this.handled = false;
@@ -64,17 +70,17 @@
this.trail = trail;
this.type = type;
this.pointer = pointer;
- this.domEvent = domEvent;
+ this.context = context;
+ this.domEvent = context.domEvent;
+ this.activeElement = context.activeElement;
this.currentTarget = null;
this.target = trail.lastNode();
// TODO: don't require check on domEvent (seems sometimes this is passed as null as a hack?)
- this.isPrimary = !( pointer instanceof Mouse ) || !domEvent || ( domEvent as unknown as MouseEvent ).button === 0;
+ this.isPrimary = !( pointer instanceof Mouse ) || !this.domEvent || ( this.domEvent as unknown as MouseEvent ).button === 0;
// Store the last-used non-null DOM event for future use if required.
- if ( domEvent ) {
- pointer.lastDOMEvent = domEvent;
- }
+ pointer.lastEventContext = context;
}
/**
Index: scenery/js/input/DownUpListener.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/DownUpListener.js b/scenery/js/input/DownUpListener.js
--- a/scenery/js/input/DownUpListener.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/DownUpListener.js (date 1682524998261)
@@ -9,7 +9,7 @@
import deprecationWarning from '../../../phet-core/js/deprecationWarning.js';
import merge from '../../../phet-core/js/merge.js';
import PhetioObject from '../../../tandem/js/PhetioObject.js';
-import { Mouse, scenery, SceneryEvent, Trail } from '../imports.js';
+import { EventContext, Mouse, scenery, SceneryEvent, Trail } from '../imports.js';
/**
* @deprecated - use PressListener instead
@@ -193,9 +193,11 @@
this.interrupted = true;
+ const context = EventContext.createSynthetic();
+
// We create a synthetic event here, as there is no available event here.
// Empty trail, so that it for-sure isn't under our downTrail (guaranteeing that isInside will be false).
- const syntheticEvent = new SceneryEvent( new Trail(), 'synthetic', this.pointer, null );
+ const syntheticEvent = new SceneryEvent( new Trail(), 'synthetic', this.pointer, context );
syntheticEvent.currentTarget = this.downCurrentTarget;
this.buttonUp( syntheticEvent );
Index: scenery/js/input/BrowserEvents.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/BrowserEvents.js b/scenery/js/input/BrowserEvents.js
--- a/scenery/js/input/BrowserEvents.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/BrowserEvents.js (date 1682537924139)
@@ -8,7 +8,7 @@
import arrayRemove from '../../../phet-core/js/arrayRemove.js';
import platform from '../../../phet-core/js/platform.js';
-import { BatchedDOMEventType, Display, Features, FocusManager, globalKeyStateTracker, PDOMUtils, scenery } from '../imports.js';
+import { BatchedDOMEventType, Display, EventContext, Features, FocusManager, globalKeyStateTracker, PDOMUtils, scenery } from '../imports.js';
// Sometimes we need to add a listener that does absolutely nothing
const noop = () => {};
@@ -17,6 +17,12 @@
let isGloballyAttached = false;
const BrowserEvents = {
+
+ // Prevents focus related event callbacks from being dispatched - scenery internal operations might change
+ // focus temporarily, we don't want event listeners to be called in this case because they are transient and not
+ // caused by user interaction.
+ blockFocusCallbacks: false,
+
/**
* Adds a Display to the list of displays that will be notified of input events.
* @public
@@ -318,7 +324,7 @@
* Sets an event from the window to be batched on all of the displays.
* @private
*
- * @param {Event} domEvent
+ * @param {EventContext} eventContext
* @param {BatchedDOMEventType} batchType - TODO: turn to full enumeration?
* @param {string} inputCallbackName - e.g. 'mouseDown', will trigger Input.mouseDown
* @param {boolean} triggerImmediate - Whether this will be force-executed now, causing all batched events to fire.
@@ -326,14 +332,17 @@
* necessary for certain security-sensitive actions (like triggering
* full-screen).
*/
- batchWindowEvent( domEvent, batchType, inputCallbackName, triggerImmediate ) {
+ batchWindowEvent( eventContext, batchType, inputCallbackName, triggerImmediate ) {
// NOTE: For now, we don't check whether the event is actually within the display's boundingClientRect. Most
// displays will want to receive events outside of their bounds (especially for checking drags and mouse-ups
// outside of their bounds).
for ( let i = 0; i < this.attachedDisplays.length; i++ ) {
const display = this.attachedDisplays[ i ];
const input = display._input;
- input.batchEvent( domEvent, batchType, input[ inputCallbackName ], triggerImmediate );
+
+ if ( !BrowserEvents.blockFocusCallbacks || ( inputCallbackName !== 'focusIn' && inputCallbackName !== 'focusOut' ) ) {
+ input.batchEvent( eventContext, batchType, input[ inputCallbackName ], triggerImmediate );
+ }
}
},
@@ -347,12 +356,15 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'pointerdown' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
if ( domEvent.pointerType === 'mouse' ) {
Display.userGestureEmitter.emit();
}
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerDown', false );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.POINTER_TYPE, 'pointerDown', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -367,10 +379,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'pointerup' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerUp', true );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.POINTER_TYPE, 'pointerUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -386,7 +401,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -402,7 +417,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerOver', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerOver', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -418,7 +433,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerOut', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerOut', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -434,7 +449,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'pointerCancel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'pointerCancel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -450,7 +465,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'gotPointerCapture', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'gotPointerCapture', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -466,7 +481,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.POINTER_TYPE, 'lostPointerCapture', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.POINTER_TYPE, 'lostPointerCapture', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -482,7 +497,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerDown', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerDown', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -498,7 +513,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerUp', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -514,7 +529,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -530,7 +545,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOver', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOver', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -546,7 +561,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOut', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerOut', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -562,7 +577,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MS_POINTER_TYPE, 'pointerCancel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MS_POINTER_TYPE, 'pointerCancel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -578,7 +593,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchStart', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.TOUCH_TYPE, 'touchStart', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -593,10 +608,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'touchend' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchEnd', true );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.TOUCH_TYPE, 'touchEnd', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -612,7 +630,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.TOUCH_TYPE, 'touchMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -628,7 +646,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.TOUCH_TYPE, 'touchCancel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.TOUCH_TYPE, 'touchCancel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -643,10 +661,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'mousedown' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseDown', false );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.MOUSE_TYPE, 'mouseDown', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -661,10 +682,13 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.OnInput( 'mouseup' );
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
+ // Get the active element BEFORE any actions are taken
+ const eventContext = new EventContext( domEvent );
+
Display.userGestureEmitter.emit();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseUp', true );
+ BrowserEvents.batchWindowEvent( eventContext, BatchedDOMEventType.MOUSE_TYPE, 'mouseUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -680,7 +704,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseMove', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MOUSE_TYPE, 'mouseMove', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -696,7 +720,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseOver', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MOUSE_TYPE, 'mouseOver', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -712,7 +736,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.MOUSE_TYPE, 'mouseOut', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.MOUSE_TYPE, 'mouseOut', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -728,7 +752,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.WHEEL_TYPE, 'wheel', false );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.WHEEL_TYPE, 'wheel', false );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -738,7 +762,12 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusIn', true );
+
+ // if ( domEvent.target.id === 'display1-primary-30-44-2795-2802-2797-2806-3012-3011-2992' ) {
+ // debugger;
+ // }
+
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'focusIn', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -748,7 +777,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'focusOut', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'focusOut', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -758,7 +787,8 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'input', true );
+
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'input', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -768,7 +798,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'change', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'change', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -778,7 +808,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'click', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'click', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -788,7 +818,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyDown', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'keyDown', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
},
@@ -798,7 +828,7 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- BrowserEvents.batchWindowEvent( domEvent, BatchedDOMEventType.ALT_TYPE, 'keyUp', true );
+ BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'keyUp', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
}
Index: scenery/js/input/InputFuzzer.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/InputFuzzer.js b/scenery/js/input/InputFuzzer.js
--- a/scenery/js/input/InputFuzzer.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/InputFuzzer.js (date 1682524998345)
@@ -8,7 +8,7 @@
import Random from '../../../dot/js/Random.js';
import Vector2 from '../../../dot/js/Vector2.js';
-import { scenery } from '../imports.js';
+import { EventContext, scenery } from '../imports.js';
class InputFuzzer {
/**
@@ -211,7 +211,7 @@
const event = this.createTouchEvent( 'touchstart', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchStart( touch.id, touch.position, event );
+ this.display._input.touchStart( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -226,7 +226,7 @@
const event = this.createTouchEvent( 'touchmove', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchMove( touch.id, touch.position, event );
+ this.display._input.touchMove( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -239,7 +239,7 @@
const event = this.createTouchEvent( 'touchend', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchEnd( touch.id, touch.position, event );
+ this.display._input.touchEnd( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -252,7 +252,7 @@
const event = this.createTouchEvent( 'touchcancel', [ touch ] );
this.display._input.validatePointers();
- this.display._input.touchCancel( touch.id, touch.position, event );
+ this.display._input.touchCancel( touch.id, touch.position, new EventContext( event ) );
}
/**
@@ -272,11 +272,11 @@
this.display._input.validatePointers();
if ( this.isMouseDown ) {
- this.display._input.mouseUp( this.mousePosition, domEvent );
+ this.display._input.mouseUp( this.mousePosition, new EventContext( domEvent ) );
this.isMouseDown = false;
}
else {
- this.display._input.mouseDown( null, this.mousePosition, domEvent );
+ this.display._input.mouseDown( null, this.mousePosition, new EventContext( domEvent ) );
this.isMouseDown = true;
}
}
@@ -299,7 +299,7 @@
null );
this.display._input.validatePointers();
- this.display._input.mouseMove( this.mousePosition, domEvent );
+ this.display._input.mouseMove( this.mousePosition, new EventContext( domEvent ) );
}
}
Index: scenery/js/display/Display.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/display/Display.ts b/scenery/js/display/Display.ts
--- a/scenery/js/display/Display.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/display/Display.ts (date 1682538564960)
@@ -285,11 +285,6 @@
private _focusRootNode?: Node;
private _focusOverlay?: HighlightOverlay;
- // (if accessible) During DOM operations where HTML elements are removed from and
- // reinserted into the PDOM, event callbacks related to focus should be blocked as these are internal operations
- // unrelated to application behavior user input, see https://github.com/phetsims/scenery/issues/925
- public blockFocusCallbacks?: boolean;
-
// (scenery-internal, if accessible)
public _rootPDOMInstance?: PDOMInstance;
@@ -480,8 +475,6 @@
}
if ( this._accessible ) {
- this.blockFocusCallbacks = false;
-
this._rootPDOMInstance = PDOMInstance.pool.create( null, this, new Trail() );
sceneryLog && sceneryLog.PDOMInstance && sceneryLog.PDOMInstance(
`Display root instance: ${this._rootPDOMInstance.toString()}` );
Index: scenery/js/input/Pointer.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/Pointer.ts b/scenery/js/input/Pointer.ts
--- a/scenery/js/input/Pointer.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/Pointer.ts (date 1682524998364)
@@ -30,7 +30,7 @@
import IOType from '../../../tandem/js/types/IOType.js';
import StringIO from '../../../tandem/js/types/StringIO.js';
import TAttachableInputListener from './TAttachableInputListener.js';
-import { scenery, SceneryEvent, TInputListener, Trail } from '../imports.js';
+import { EventContext, scenery, SceneryEvent, TInputListener, Trail } from '../imports.js';
export class Intent extends EnumerationValue {
// listener attached to the pointer will be used for dragging
@@ -88,7 +88,7 @@
// (scenery-internal) - Recorded and exposed so that it can be provided to events when there
// is no "immediate" DOM event (e.g. when a node moves UNDER a pointer and triggers a touch-snag).
- public lastDOMEvent: Event | null;
+ public lastEventContext: EventContext | null;
// A Pointer can be assigned an intent when a listener is attached to initiate or prevent
// certain behavior for the life of the listener. Other listeners can observe the Intents on the Pointer and
@@ -136,7 +136,7 @@
this._listeners = [];
this._attachedListener = null;
this._cursor = null;
- this.lastDOMEvent = null;
+ this.lastEventContext = null;
this._intents = [];
this._pointerCaptured = false;
this._listenerForDragReserve = null;
Index: scenery/js/listeners/SwipeListener.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/listeners/SwipeListener.js b/scenery/js/listeners/SwipeListener.js
--- a/scenery/js/listeners/SwipeListener.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/listeners/SwipeListener.js (date 1682524998434)
@@ -162,8 +162,8 @@
// send a click event to the active element
const pdomRoot = document.getElementsByClassName( 'a11y-pdom-root' )[ 0 ];
- if ( pdomRoot && pdomRoot.contains( document.activeElement ) ) {
- document.activeElement.click();
+ if ( pdomRoot && pdomRoot.contains( event.activeElement ) ) {
+ event.activeElement.click();
}
}
}
Index: scenery/js/imports.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/imports.ts b/scenery/js/imports.ts
--- a/scenery/js/imports.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/imports.ts (date 1682524998449)
@@ -203,6 +203,7 @@
export { default as Pen } from './input/Pen.js';
export { default as PDOMPointer } from './input/PDOMPointer.js';
+export { default as EventContext, EventContextIO } from './input/EventContext.js';
export { default as SceneryEvent } from './input/SceneryEvent.js';
export { default as Input } from './input/Input.js';
Index: scenery/js/listeners/ListenerTestUtils.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/listeners/ListenerTestUtils.js b/scenery/js/listeners/ListenerTestUtils.js
--- a/scenery/js/listeners/ListenerTestUtils.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/listeners/ListenerTestUtils.js (date 1682524998395)
@@ -8,6 +8,7 @@
import Vector2 from '../../../dot/js/Vector2.js';
import Display from '../display/Display.js';
+import { EventContext } from '../imports.js';
import Node from '../nodes/Node.js';
import Rectangle from '../nodes/Rectangle.js';
@@ -32,7 +33,7 @@
null );
display._input.validatePointers();
- display._input.mouseDown( null, new Vector2( x, y ), domEvent );
+ display._input.mouseDown( null, new Vector2( x, y ), new EventContext( domEvent ) );
},
/**
@@ -54,7 +55,7 @@
null );
display._input.validatePointers();
- display._input.mouseUp( new Vector2( x, y ), domEvent );
+ display._input.mouseUp( new Vector2( x, y ), new EventContext( domEvent ) );
},
/**
@@ -77,7 +78,7 @@
display._input.validatePointers();
- display._input.mouseMove( new Vector2( x, y ), domEvent );
+ display._input.mouseMove( new Vector2( x, y ), new EventContext( domEvent ) );
},
/**
Index: scenery/js/input/Input.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/Input.ts b/scenery/js/input/Input.ts
--- a/scenery/js/input/Input.ts (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/input/Input.ts (date 1682537900713)
@@ -173,7 +173,7 @@
import Tandem from '../../../tandem/js/Tandem.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import NumberIO from '../../../tandem/js/types/NumberIO.js';
-import { BatchedDOMEvent, BatchedDOMEventCallback, BatchedDOMEventType, BrowserEvents, Display, EventIO, Mouse, Node, PDOMInstance, PDOMPointer, PDOMUtils, Pen, Pointer, scenery, SceneryEvent, SceneryListenerFunction, SupportedEventTypes, TInputListener, Touch, Trail, WindowTouch } from '../imports.js';
+import { BatchedDOMEvent, BatchedDOMEventCallback, BatchedDOMEventType, BrowserEvents, Display, EventContext, EventContextIO, Mouse, Node, PDOMInstance, PDOMPointer, PDOMUtils, Pen, Pointer, scenery, SceneryEvent, SceneryListenerFunction, SupportedEventTypes, TInputListener, Touch, Trail, WindowTouch } from '../imports.js';
import PhetioObject, { PhetioObjectOptions } from '../../../tandem/js/PhetioObject.js';
import IOType from '../../../tandem/js/types/IOType.js';
import ArrayIO from '../../../tandem/js/types/ArrayIO.js';
@@ -302,31 +302,31 @@
// This is a high frequency event that is necessary for reproducible playbacks
private readonly validatePointersAction: PhetioAction;
- private readonly mouseUpAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly mouseDownAction: PhetioAction<[ number, Vector2, MouseEvent ]>;
- private readonly mouseMoveAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly mouseOverAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly mouseOutAction: PhetioAction<[ Vector2, MouseEvent ]>;
- private readonly wheelScrollAction: PhetioAction<[ WheelEvent ]>;
- private readonly touchStartAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly touchEndAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly touchMoveAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly touchCancelAction: PhetioAction<[ number, Vector2, TouchEvent | PointerEvent ]>;
- private readonly penStartAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly penEndAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly penMoveAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly penCancelAction: PhetioAction<[ number, Vector2, PointerEvent ]>;
- private readonly gotPointerCaptureAction: PhetioAction<[ number, Event ]>;
- private readonly lostPointerCaptureAction: PhetioAction<[ number, Event ]>;
+ private readonly mouseUpAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseDownAction: PhetioAction<[ number, Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseMoveAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseOverAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly mouseOutAction: PhetioAction<[ Vector2, EventContext<MouseEvent> ]>;
+ private readonly wheelScrollAction: PhetioAction<[ EventContext<WheelEvent> ]>;
+ private readonly touchStartAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly touchEndAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly touchMoveAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly touchCancelAction: PhetioAction<[ number, Vector2, EventContext<TouchEvent | PointerEvent> ]>;
+ private readonly penStartAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly penEndAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly penMoveAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly penCancelAction: PhetioAction<[ number, Vector2, EventContext<PointerEvent> ]>;
+ private readonly gotPointerCaptureAction: PhetioAction<[ number, EventContext ]>;
+ private readonly lostPointerCaptureAction: PhetioAction<[ number, EventContext ]>;
// If accessible
- private readonly focusinAction: PhetioAction<[ FocusEvent ]>;
- private readonly focusoutAction: PhetioAction<[ FocusEvent ]>;
- private readonly clickAction: PhetioAction<[ MouseEvent ]>;
- private readonly inputAction: PhetioAction<[ Event | InputEvent ]>;
- private readonly changeAction: PhetioAction<[ Event ]>;
- private readonly keydownAction: PhetioAction<[ KeyboardEvent ]>;
- private readonly keyupAction: PhetioAction<[ KeyboardEvent ]>;
+ private readonly focusinAction: PhetioAction<[ EventContext<FocusEvent> ]>;
+ private readonly focusoutAction: PhetioAction<[ EventContext<FocusEvent> ]>;
+ private readonly clickAction: PhetioAction<[ EventContext<MouseEvent> ]>;
+ private readonly inputAction: PhetioAction<[ EventContext<Event | InputEvent> ]>;
+ private readonly changeAction: PhetioAction<[ EventContext ]>;
+ private readonly keydownAction: PhetioAction<[ EventContext<KeyboardEvent> ]>;
+ private readonly keyupAction: PhetioAction<[ EventContext<KeyboardEvent> ]>;
public static readonly InputIO = new IOType<Input>( 'InputIO', {
valueType: Input,
@@ -386,7 +386,7 @@
while ( i-- ) {
const pointer = this.pointers[ i ];
if ( pointer.point && pointer !== this.pdomPointer ) {
- this.branchChangeEvents<Event>( pointer, pointer.lastDOMEvent, false );
+ this.branchChangeEvents<Event>( pointer, pointer.lastEventContext || EventContext.createSynthetic(), false );
}
}
}, {
@@ -395,54 +395,54 @@
phetioHighFrequency: true
} );
- this.mouseUpAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseUpAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.id = null;
- this.upEvent<MouseEvent>( mouse, event, point );
+ this.upEvent<MouseEvent>( mouse, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'mouseUpAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a mouse button is released.'
} );
- this.mouseDownAction = new PhetioAction( ( id: number, point: Vector2, event: MouseEvent ) => {
+ this.mouseDownAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.id = id;
- this.downEvent<MouseEvent>( mouse, event, point );
+ this.downEvent<MouseEvent>( mouse, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'mouseDownAction' ),
parameters: [
{ name: 'id', phetioType: NullableIO( NumberIO ) },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a mouse button is pressed.'
} );
- this.mouseMoveAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseMoveAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.move( point );
- this.moveEvent<MouseEvent>( mouse, event );
+ this.moveEvent<MouseEvent>( mouse, context );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'mouseMoveAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse is moved.',
phetioHighFrequency: true
} );
- this.mouseOverAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseOverAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.over( point );
// TODO: how to handle mouse-over (and log it)... are we changing the pointer.point without a branch change?
@@ -451,13 +451,13 @@
tandem: options.tandem.createTandem( 'mouseOverAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse is moved while on the sim.'
} );
- this.mouseOutAction = new PhetioAction( ( point: Vector2, event: MouseEvent ) => {
+ this.mouseOutAction = new PhetioAction( ( point: Vector2, context: EventContext<MouseEvent> ) => {
const mouse = this.ensureMouse( point );
mouse.out( point );
// TODO: how to handle mouse-out (and log it)... are we changing the pointer.point without a branch change?
@@ -466,13 +466,15 @@
tandem: options.tandem.createTandem( 'mouseOutAction' ),
parameters: [
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse moves out of the display.'
} );
- this.wheelScrollAction = new PhetioAction( ( event: WheelEvent ) => {
+ this.wheelScrollAction = new PhetioAction( ( context: EventContext<WheelEvent> ) => {
+ const event = context.domEvent;
+
const mouse = this.ensureMouse( this.pointFromEvent( event ) );
mouse.wheel( event );
@@ -480,40 +482,40 @@
// TODO: Can we set the mouse location based on the wheel event?
if ( mouse.point ) {
const trail = this.rootNode.trailUnderPointer( mouse ) || new Trail( this.rootNode );
- this.dispatchEvent<WheelEvent>( trail, 'wheel', mouse, event, true );
+ this.dispatchEvent<WheelEvent>( trail, 'wheel', mouse, context, true );
}
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'wheelScrollAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the mouse wheel scrolls.',
phetioHighFrequency: true
} );
- this.touchStartAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
- const touch = new Touch( id, point, event );
+ this.touchStartAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
+ const touch = new Touch( id, point, context.domEvent );
this.addPointer( touch );
- this.downEvent<TouchEvent | PointerEvent>( touch, event, point );
+ this.downEvent<TouchEvent | PointerEvent>( touch, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'touchStartAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch begins.'
} );
- this.touchEndAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
+ this.touchEndAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
const touch = this.findPointerById( id ) as Touch | null;
if ( touch ) {
assert && assert( touch instanceof Touch ); // eslint-disable-line no-simple-type-checking-assertions, bad-sim-text
- this.upEvent<TouchEvent | PointerEvent>( touch, event, point );
+ this.upEvent<TouchEvent | PointerEvent>( touch, context, point );
this.removePointer( touch );
}
}, {
@@ -522,18 +524,18 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch ends.'
} );
- this.touchMoveAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
+ this.touchMoveAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
const touch = this.findPointerById( id ) as Touch | null;
if ( touch ) {
assert && assert( touch instanceof Touch ); // eslint-disable-line no-simple-type-checking-assertions, bad-sim-text
touch.move( point );
- this.moveEvent<TouchEvent | PointerEvent>( touch, event );
+ this.moveEvent<TouchEvent | PointerEvent>( touch, context );
}
}, {
phetioPlayback: true,
@@ -541,18 +543,18 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch moves.',
phetioHighFrequency: true
} );
- this.touchCancelAction = new PhetioAction( ( id: number, point: Vector2, event: TouchEvent | PointerEvent ) => {
+ this.touchCancelAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ) => {
const touch = this.findPointerById( id ) as Touch | null;
if ( touch ) {
assert && assert( touch instanceof Touch ); // eslint-disable-line no-simple-type-checking-assertions, bad-sim-text
- this.cancelEvent<TouchEvent | PointerEvent>( touch, event, point );
+ this.cancelEvent<TouchEvent | PointerEvent>( touch, context, point );
this.removePointer( touch );
}
}, {
@@ -561,32 +563,32 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a touch is canceled.'
} );
- this.penStartAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
- const pen = new Pen( id, point, event );
+ this.penStartAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
+ const pen = new Pen( id, point, context.domEvent );
this.addPointer( pen );
- this.downEvent<PointerEvent>( pen, event, point );
+ this.downEvent<PointerEvent>( pen, context, point );
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'penStartAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen touches the screen.'
} );
- this.penEndAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
+ this.penEndAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
const pen = this.findPointerById( id ) as Pen | null;
if ( pen ) {
- this.upEvent<PointerEvent>( pen, event, point );
+ this.upEvent<PointerEvent>( pen, context, point );
this.removePointer( pen );
}
}, {
@@ -595,17 +597,17 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen is lifted.'
} );
- this.penMoveAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
+ this.penMoveAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
const pen = this.findPointerById( id ) as Pen | null;
if ( pen ) {
pen.move( point );
- this.moveEvent<PointerEvent>( pen, event );
+ this.moveEvent<PointerEvent>( pen, context );
}
}, {
phetioPlayback: true,
@@ -613,17 +615,17 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen is moved.',
phetioHighFrequency: true
} );
- this.penCancelAction = new PhetioAction( ( id: number, point: Vector2, event: PointerEvent ) => {
+ this.penCancelAction = new PhetioAction( ( id: number, point: Vector2, context: EventContext<PointerEvent> ) => {
const pen = this.findPointerById( id ) as Pen | null;
if ( pen ) {
- this.cancelEvent<PointerEvent>( pen, event, point );
+ this.cancelEvent<PointerEvent>( pen, context, point );
this.removePointer( pen );
}
}, {
@@ -632,13 +634,13 @@
parameters: [
{ name: 'id', phetioType: NumberIO },
{ name: 'point', phetioType: Vector2.Vector2IO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pen is canceled.'
} );
- this.gotPointerCaptureAction = new PhetioAction( ( id: number, event: Event ) => {
+ this.gotPointerCaptureAction = new PhetioAction( ( id: number, context: EventContext ) => {
const pointer = this.findPointerById( id );
if ( pointer ) {
@@ -649,14 +651,14 @@
tandem: options.tandem.createTandem( 'gotPointerCaptureAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pointer is captured (normally at the start of an interaction)',
phetioHighFrequency: true
} );
- this.lostPointerCaptureAction = new PhetioAction( ( id: number, event: Event ) => {
+ this.lostPointerCaptureAction = new PhetioAction( ( id: number, context: EventContext ) => {
const pointer = this.findPointerById( id );
if ( pointer ) {
@@ -667,64 +669,54 @@
tandem: options.tandem.createTandem( 'lostPointerCaptureAction' ),
parameters: [
{ name: 'id', phetioType: NumberIO },
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when a pointer loses its capture (normally at the end of an interaction)',
phetioHighFrequency: true
} );
- this.focusinAction = new PhetioAction( ( event: FocusEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'focusin' );
+ this.focusinAction = new PhetioAction( ( context: EventContext<FocusEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'focusin' );
if ( !trail ) {
return;
}
- // ignore any focusout callbacks if they are initiated due to implementation details in PDOM manipulation
- if ( this.display.blockFocusCallbacks ) {
- return;
- }
-
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusin(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusin(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<FocusEvent>( trail, 'focus', event, false );
- this.dispatchPDOMEvent<FocusEvent>( trail, 'focusin', event, true );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'focus', context, false );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'focusin', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'focusinAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the focusin DOM event.'
} );
- this.focusoutAction = new PhetioAction( ( event: FocusEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'focusout' );
+ this.focusoutAction = new PhetioAction( ( context: EventContext<FocusEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'focusout' );
if ( !trail ) {
return;
}
- // ignore any focusout callbacks if they are initiated due to implementation details in PDOM manipulation
- if ( this.display.blockFocusCallbacks ) {
- return;
- }
-
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<FocusEvent>( trail, 'blur', event, false );
- this.dispatchPDOMEvent<FocusEvent>( trail, 'focusout', event, true );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'blur', context, false );
+ this.dispatchPDOMEvent<FocusEvent>( trail, 'focusout', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'focusoutAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the focusout DOM event.'
@@ -732,111 +724,111 @@
// https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event notes that the click action should result
// in a MouseEvent
- this.clickAction = new PhetioAction( ( event: MouseEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'click' );
+ this.clickAction = new PhetioAction( ( context: EventContext<MouseEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'click' );
if ( !trail ) {
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `click(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `click(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<MouseEvent>( trail, 'click', event, true );
+ this.dispatchPDOMEvent<MouseEvent>( trail, 'click', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'clickAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the click DOM event.'
} );
- this.inputAction = new PhetioAction( ( event: Event | InputEvent ) => {
- const trail = this.getPDOMEventTrail( event, 'input' );
+ this.inputAction = new PhetioAction( ( context: EventContext<Event | InputEvent> ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'input' );
if ( !trail ) {
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `input(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `input(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<Event | InputEvent>( trail, 'input', event, true );
+ this.dispatchPDOMEvent<Event | InputEvent>( trail, 'input', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'inputAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the input DOM event.'
} );
- this.changeAction = new PhetioAction( ( event: Event ) => {
- const trail = this.getPDOMEventTrail( event, 'change' );
+ this.changeAction = new PhetioAction( ( context: EventContext ) => {
+ const trail = this.getPDOMEventTrail( context.domEvent, 'change' );
if ( !trail ) {
return;
}
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `change(${Input.debugText( null, event )});` );
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `change(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchPDOMEvent<Event>( trail, 'change', event, true );
+ this.dispatchPDOMEvent<Event>( trail, 'change', context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'changeAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the change DOM event.'
} );
- this.keydownAction = new PhetioAction( ( event: KeyboardEvent ) => {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keydown(${Input.debugText( null, event )});` );
+ this.keydownAction = new PhetioAction( ( context: EventContext<KeyboardEvent> ) => {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keydown(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', event, true );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', context, true );
- const trail = this.getPDOMEventTrail( event, 'keydown' );
- trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keydown', event, true );
+ const trail = this.getPDOMEventTrail( context.domEvent, 'keydown' );
+ trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keydown', context, true );
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', event, false );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeydown', context, false );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'keydownAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the keydown DOM event.'
} );
- this.keyupAction = new PhetioAction( ( event: KeyboardEvent ) => {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyup(${Input.debugText( null, event )});` );
+ this.keyupAction = new PhetioAction( ( context: EventContext<KeyboardEvent> ) => {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyup(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', event, true );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', context, true );
- const trail = this.getPDOMEventTrail( event, 'keydown' );
- trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keyup', event, true );
+ const trail = this.getPDOMEventTrail( context.domEvent, 'keydown' );
+ trail && this.dispatchPDOMEvent<KeyboardEvent>( trail, 'keyup', context, true );
- this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', event, false );
+ this.dispatchGlobalEvent<KeyboardEvent>( 'globalkeyup', context, false );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}, {
phetioPlayback: true,
tandem: options.tandem.createTandem( 'keyupAction' ),
parameters: [
- { name: 'event', phetioType: EventIO }
+ { name: 'context', phetioType: EventContextIO }
],
phetioEventType: EventType.USER,
phetioDocumentation: 'Emits when the PDOM root gets the keyup DOM event.'
@@ -855,20 +847,20 @@
/**
* Called to batch a raw DOM event (which may be immediately fired, depending on the settings). (scenery-internal)
*
- * @param domEvent
+ * @param context
* @param batchType - See BatchedDOMEvent's "enumeration"
* @param callback - Parameter types defined by the batchType. See BatchedDOMEvent for details
* @param triggerImmediate - Certain events can force immediate action, since browsers like Chrome
* only allow certain operations in the callback for a user gesture (e.g. like
* a mouseup to open a window).
*/
- public batchEvent( domEvent: Event, batchType: BatchedDOMEventType, callback: BatchedDOMEventCallback, triggerImmediate: boolean ): void {
+ public batchEvent( context: EventContext, batchType: BatchedDOMEventType, callback: BatchedDOMEventCallback, triggerImmediate: boolean ): void {
sceneryLog && sceneryLog.InputEvent && sceneryLog.InputEvent( 'Input.batchEvent' );
sceneryLog && sceneryLog.InputEvent && sceneryLog.push();
// If our display is not interactive, do not respond to any events (but still prevent default)
if ( this.display.interactive ) {
- this.batchedEvents.push( BatchedDOMEvent.pool.create( domEvent, batchType, callback ) );
+ this.batchedEvents.push( BatchedDOMEvent.pool.create( context, batchType, callback ) );
if ( triggerImmediate || !this.batchDOMEvents ) {
this.fireBatchedEvents();
}
@@ -884,7 +876,7 @@
( callback !== this.mouseDown || platform.edge ) &&
batchType !== BatchedDOMEventType.ALT_TYPE ) {
// We cannot prevent a passive event, so don't try
- domEvent.preventDefault();
+ context.domEvent.preventDefault();
}
sceneryLog && sceneryLog.InputEvent && sceneryLog.pop();
@@ -945,11 +937,6 @@
* Removes all non-Mouse pointers from internal tracking. (scenery-internal)
*/
public removeTemporaryPointers(): void {
- // TODO: Just null this out, instead of creating a fake event?
- const fakeDomEvent = {
- eek: 'This is a fake DOM event created in removeTemporaryPointers(), called from a Scenery exit event. Our attempt to masquerade seems unsuccessful! :('
- } as unknown as Event;
-
for ( let i = this.pointers.length - 1; i >= 0; i-- ) {
const pointer = this.pointers[ i ];
if ( !( pointer instanceof Mouse ) ) {
@@ -957,7 +944,7 @@
// Send exit events. As we can't get a DOM event, we'll send a fake object instead.
const exitTrail = pointer.trail || new Trail( this.rootNode );
- this.exitEvents( pointer, fakeDomEvent, exitTrail, 0, true );
+ this.exitEvents( pointer, EventContext.createSynthetic(), exitTrail, 0, true );
}
}
}
@@ -1107,7 +1094,7 @@
* Steps to dispatch a pdom-related event. Before dispatch, the PDOMPointer is initialized if it
* hasn't been created yet and a userGestureEmitter emits to indicate that a user has begun an interaction.
*/
- private dispatchPDOMEvent<DOMEvent extends Event>( trail: Trail, eventType: SupportedEventTypes, domEvent: DOMEvent, bubbles: boolean ): void {
+ private dispatchPDOMEvent<DOMEvent extends Event>( trail: Trail, eventType: SupportedEventTypes, context: EventContext<DOMEvent>, bubbles: boolean ): void {
this.ensurePDOMPointer().updateTrail( trail );
@@ -1116,6 +1103,8 @@
Display.userGestureEmitter.emit();
}
+ const domEvent = context.domEvent;
+
// This workaround hopefully won't be here forever, see ParallelDOM.setExcludeLabelSiblingFromInput() and https://github.com/phetsims/a11y-research/issues/156
if ( !( domEvent.target && ( domEvent.target as Element ).hasAttribute( PDOMUtils.DATA_EXCLUDE_FROM_INPUT ) ) ) {
@@ -1127,16 +1116,15 @@
trail = new Trail( [] );
}
assert && assert( this.pdomPointer );
- this.dispatchEvent<DOMEvent>( trail, eventType, this.pdomPointer!, domEvent, bubbles );
+ this.dispatchEvent<DOMEvent>( trail, eventType, this.pdomPointer!, context, bubbles );
}
}
- private dispatchGlobalEvent<DOMEvent extends Event>( eventType: SupportedEventTypes, domEvent: DOMEvent, capture: boolean ): void {
-
+ private dispatchGlobalEvent<DOMEvent extends Event>( eventType: SupportedEventTypes, context: EventContext<DOMEvent>, capture: boolean ): void {
this.ensurePDOMPointer();
assert && assert( this.pdomPointer );
const pointer = this.pdomPointer!;
- const inputEvent = new SceneryEvent<DOMEvent>( new Trail(), eventType, pointer, domEvent );
+ const inputEvent = new SceneryEvent<DOMEvent>( new Trail(), eventType, pointer, context );
const recursiveGlobalDispatch = ( node: Node ) => {
if ( !node.isDisposed && node.isVisible() && node.isInputEnabled() ) {
@@ -1212,10 +1200,10 @@
* NOTE: This may also be called from the pointer event handler (pointerDown) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public mouseDown( id: number, point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseDown('${id}', ${Input.debugText( point, event )});` );
+ public mouseDown( id: number, point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseDown('${id}', ${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseDownAction.execute( id, point, event );
+ this.mouseDownAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1225,10 +1213,10 @@
* NOTE: This may also be called from the pointer event handler (pointerUp) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public mouseUp( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseUp(${Input.debugText( point, event )});` );
+ public mouseUp( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseUp(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseUpAction.execute( point, event );
+ this.mouseUpAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1238,40 +1226,40 @@
* NOTE: This may also be called from the pointer event handler (pointerMove) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public mouseMove( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseMove(${Input.debugText( point, event )});` );
+ public mouseMove( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseMove(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseMoveAction.execute( point, event );
+ this.mouseMoveAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Triggers a logical mouseover event (this does NOT correspond to the Scenery event, since this is for the display) (scenery-internal)
*/
- public mouseOver( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOver(${Input.debugText( point, event )});` );
+ public mouseOver( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOver(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseOverAction.execute( point, event );
+ this.mouseOverAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Triggers a logical mouseout event (this does NOT correspond to the Scenery event, since this is for the display) (scenery-internal)
*/
- public mouseOut( point: Vector2, event: MouseEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOut(${Input.debugText( point, event )});` );
+ public mouseOut( point: Vector2, context: EventContext<MouseEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `mouseOut(${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.mouseOutAction.execute( point, event );
+ this.mouseOutAction.execute( point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Triggers a logical mouse-wheel/scroll event. (scenery-internal)
*/
- public wheel( event: WheelEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `wheel(${Input.debugText( null, event )});` );
+ public wheel( context: EventContext<WheelEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `wheel(${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.wheelScrollAction.execute( event );
+ this.wheelScrollAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1281,11 +1269,11 @@
* NOTE: This may also be called from the pointer event handler (pointerDown) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchStart( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchStart('${id}',${Input.debugText( point, event )});` );
+ public touchStart( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchStart('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchStartAction.execute( id, point, event );
+ this.touchStartAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1296,11 +1284,11 @@
* NOTE: This may also be called from the pointer event handler (pointerUp) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchEnd( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchEnd('${id}',${Input.debugText( point, event )});` );
+ public touchEnd( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchEnd('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchEndAction.execute( id, point, event );
+ this.touchEndAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1311,10 +1299,10 @@
* NOTE: This may also be called from the pointer event handler (pointerMove) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchMove( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchMove('${id}',${Input.debugText( point, event )});` );
+ public touchMove( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchMove('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchMoveAction.execute( id, point, event );
+ this.touchMoveAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1324,10 +1312,10 @@
* NOTE: This may also be called from the pointer event handler (pointerCancel) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public touchCancel( id: number, point: Vector2, event: TouchEvent | PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchCancel('${id}',${Input.debugText( point, event )});` );
+ public touchCancel( id: number, point: Vector2, context: EventContext<TouchEvent | PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `touchCancel('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.touchCancelAction.execute( id, point, event );
+ this.touchCancelAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1337,10 +1325,10 @@
* NOTE: This may also be called from the pointer event handler (pointerDown) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penStart( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penStart('${id}',${Input.debugText( point, event )});` );
+ public penStart( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penStart('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penStartAction.execute( id, point, event );
+ this.penStartAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1350,10 +1338,10 @@
* NOTE: This may also be called from the pointer event handler (pointerUp) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penEnd( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penEnd('${id}',${Input.debugText( point, event )});` );
+ public penEnd( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penEnd('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penEndAction.execute( id, point, event );
+ this.penEndAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1363,10 +1351,10 @@
* NOTE: This may also be called from the pointer event handler (pointerMove) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penMove( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penMove('${id}',${Input.debugText( point, event )});` );
+ public penMove( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penMove('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penMoveAction.execute( id, point, event );
+ this.penMoveAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1376,37 +1364,37 @@
* NOTE: This may also be called from the pointer event handler (pointerCancel) or from things like fuzzing or
* playback. The event may be "faked" for certain purposes.
*/
- public penCancel( id: number, point: Vector2, event: PointerEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `penCancel('${id}',${Input.debugText( point, event )});` );
+ public penCancel( id: number, point: Vector2, context: EventContext<PointerEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `penCancel('${id}',${Input.debugText( point, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.penCancelAction.execute( id, point, event );
+ this.penCancelAction.execute( id, point, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Handles a pointerdown event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerDown( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerDown( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// In IE for pointer down events, we want to make sure than the next interactions off the page are sent to
// this element (it will bubble). See https://github.com/phetsims/scenery/issues/464 and
// http://news.qooxdoo.org/mouse-capturing.
const target = this.attachToWindow ? document.body : this.display.domElement;
- if ( target.setPointerCapture && event.pointerId ) {
+ if ( target.setPointerCapture && context.domEvent.pointerId ) {
// NOTE: This will error out if run on a playback destination, where a pointer with the given ID does not exist.
- target.setPointerCapture( event.pointerId );
+ target.setPointerCapture( context.domEvent.pointerId );
}
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
// The actual event afterwards
- this.mouseDown( id, point, event );
+ this.mouseDown( id, point, context );
break;
case 'touch':
- this.touchStart( id, point, event );
+ this.touchStart( id, point, context );
break;
case 'pen':
- this.penStart( id, point, event );
+ this.penStart( id, point, context );
break;
default:
if ( assert ) {
@@ -1418,21 +1406,21 @@
/**
* Handles a pointerup event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerUp( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerUp( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// update this outside of the Action executions so that PhET-iO event playback does not override it
- this.upTimeStamp = event.timeStamp;
+ this.upTimeStamp = context.domEvent.timeStamp;
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
- this.mouseUp( point, event );
+ this.mouseUp( point, context );
break;
case 'touch':
- this.touchEnd( id, point, event );
+ this.touchEnd( id, point, context );
break;
case 'pen':
- this.penEnd( id, point, event );
+ this.penEnd( id, point, context );
break;
default:
if ( assert ) {
@@ -1444,7 +1432,7 @@
/**
* Handles a pointercancel event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerCancel( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerCancel( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
@@ -1453,10 +1441,10 @@
}
break;
case 'touch':
- this.touchCancel( id, point, event );
+ this.touchCancel( id, point, context );
break;
case 'pen':
- this.penCancel( id, point, event );
+ this.penCancel( id, point, context );
break;
default:
if ( console.log ) {
@@ -1468,37 +1456,37 @@
/**
* Handles a gotpointercapture event, forwarding it to the proper logical event. (scenery-internal)
*/
- public gotPointerCapture( id: number, type: string, point: Vector2, event: Event ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `gotPointerCapture('${id}',${Input.debugText( null, event )});` );
+ public gotPointerCapture( id: number, type: string, point: Vector2, context: EventContext ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `gotPointerCapture('${id}',${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.gotPointerCaptureAction.execute( id, event );
+ this.gotPointerCaptureAction.execute( id, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Handles a lostpointercapture event, forwarding it to the proper logical event. (scenery-internal)
*/
- public lostPointerCapture( id: number, type: string, point: Vector2, event: Event ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `lostPointerCapture('${id}',${Input.debugText( null, event )});` );
+ public lostPointerCapture( id: number, type: string, point: Vector2, context: EventContext ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `lostPointerCapture('${id}',${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.lostPointerCaptureAction.execute( id, event );
+ this.lostPointerCaptureAction.execute( id, context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
* Handles a pointermove event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerMove( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerMove( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
type = this.handleUnknownPointerType( type, id );
switch( type ) {
case 'mouse':
- this.mouseMove( point, event );
+ this.mouseMove( point, context );
break;
case 'touch':
- this.touchMove( id, point, event );
+ this.touchMove( id, point, context );
break;
case 'pen':
- this.penMove( id, point, event );
+ this.penMove( id, point, context );
break;
default:
if ( console.log ) {
@@ -1510,7 +1498,7 @@
/**
* Handles a pointerover event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerOver( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerOver( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1518,7 +1506,7 @@
/**
* Handles a pointerout event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerOut( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerOut( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1526,7 +1514,7 @@
/**
* Handles a pointerenter event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerEnter( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerEnter( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1534,7 +1522,7 @@
/**
* Handles a pointerleave event, forwarding it to the proper logical event. (scenery-internal)
*/
- public pointerLeave( id: number, type: string, point: Vector2, event: PointerEvent ): void {
+ public pointerLeave( id: number, type: string, point: Vector2, context: EventContext<PointerEvent> ): void {
// TODO: accumulate mouse/touch info in the object if needed?
// TODO: do we want to branch change on these types of events?
}
@@ -1542,11 +1530,11 @@
/**
* Handles a focusin event, forwarding it to the proper logical event. (scenery-internal)
*/
- public focusIn( event: FocusEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusIn('${Input.debugText( null, event )});` );
+ public focusIn( context: EventContext<FocusEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusIn('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.focusinAction.execute( event );
+ this.focusinAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1554,23 +1542,23 @@
/**
* Handles a focusout event, forwarding it to the proper logical event. (scenery-internal)
*/
- public focusOut( event: FocusEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut('${Input.debugText( null, event )});` );
+ public focusOut( context: EventContext<FocusEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `focusOut('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.focusoutAction.execute( event );
+ this.focusoutAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
/**
- * Handles a input event, forwarding it to the proper logical event. (scenery-internal)
+ * Handles an input event, forwarding it to the proper logical event. (scenery-internal)
*/
- public input( event: Event | InputEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `input('${Input.debugText( null, event )});` );
+ public input( context: EventContext<Event | InputEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `input('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.inputAction.execute( event );
+ this.inputAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1578,11 +1566,11 @@
/**
* Handles a change event, forwarding it to the proper logical event. (scenery-internal)
*/
- public change( event: Event ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `change('${Input.debugText( null, event )});` );
+ public change( context: EventContext ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `change('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.changeAction.execute( event );
+ this.changeAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1590,11 +1578,11 @@
/**
* Handles a click event, forwarding it to the proper logical event. (scenery-internal)
*/
- public click( event: MouseEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `click('${Input.debugText( null, event )});` );
+ public click( context: EventContext<MouseEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `click('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.clickAction.execute( event );
+ this.clickAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1602,11 +1590,11 @@
/**
* Handles a keydown event, forwarding it to the proper logical event. (scenery-internal)
*/
- public keyDown( event: KeyboardEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyDown('${Input.debugText( null, event )});` );
+ public keyDown( context: EventContext<KeyboardEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyDown('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.keydownAction.execute( event );
+ this.keydownAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1614,11 +1602,11 @@
/**
* Handles a keyup event, forwarding it to the proper logical event. (scenery-internal)
*/
- public keyUp( event: KeyboardEvent ): void {
- sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyUp('${Input.debugText( null, event )});` );
+ public keyUp( context: EventContext<KeyboardEvent> ): void {
+ sceneryLog && sceneryLog.Input && sceneryLog.Input( `keyUp('${Input.debugText( null, context.domEvent )});` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
- this.keyupAction.execute( event );
+ this.keyupAction.execute( context );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1646,28 +1634,27 @@
/**
* Called for each logical "up" event, for any pointer type.
*/
- private upEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent, point: Vector2 ): void {
-
+ private upEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, point: Vector2 ): void {
// if the event target is within the PDOM the AT is sending a fake pointer event to the document - do not
// dispatch this since the PDOM should only handle Input.PDOM_EVENT_TYPES, and all other pointer input should
// go through the Display div. Otherwise, activation will be duplicated when we handle pointer and PDOM events
- if ( this.isTargetUnderPDOM( event.target as HTMLElement ) ) {
+ if ( this.isTargetUnderPDOM( context.domEvent.target as HTMLElement ) ) {
return;
}
- const pointChanged = pointer.up( point, event );
+ const pointChanged = pointer.up( point, context.domEvent );
sceneryLog && sceneryLog.Input && sceneryLog.Input( `upEvent ${pointer.toString()} changed:${pointChanged}` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
// We'll use this trail for the entire dispatch of this event.
- const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, event, pointChanged );
+ const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, context, pointChanged );
- this.dispatchEvent<DOMEvent>( eventTrail, 'up', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( eventTrail, 'up', pointer, context, true );
// touch pointers are transient, so fire exit/out to the trail afterwards
if ( pointer.isTouchLike() ) {
- this.exitEvents<DOMEvent>( pointer, event, eventTrail, 0, true );
+ this.exitEvents<DOMEvent>( pointer, context, eventTrail, 0, true );
}
sceneryLog && sceneryLog.Input && sceneryLog.pop();
@@ -1676,12 +1663,11 @@
/**
* Called for each logical "down" event, for any pointer type.
*/
- private downEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent, point: Vector2 ): void {
-
+ private downEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, point: Vector2 ): void {
// if the event target is within the PDOM the AT is sending a fake pointer event to the document - do not
// dispatch this since the PDOM should only handle Input.PDOM_EVENT_TYPES, and all other pointer input should
// go through the Display div. Otherwise, activation will be duplicated when we handle pointer and PDOM events
- if ( this.isTargetUnderPDOM( event.target as HTMLElement ) ) {
+ if ( this.isTargetUnderPDOM( context.domEvent.target as HTMLElement ) ) {
return;
}
@@ -1691,11 +1677,11 @@
sceneryLog && sceneryLog.Input && sceneryLog.push();
// We'll use this trail for the entire dispatch of this event.
- const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, event, pointChanged );
+ const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, context, pointChanged );
- pointer.down( event );
+ pointer.down( context.domEvent );
- this.dispatchEvent<DOMEvent>( eventTrail, 'down', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( eventTrail, 'down', pointer, context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1703,12 +1689,12 @@
/**
* Called for each logical "move" event, for any pointer type.
*/
- private moveEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent ): void {
+ private moveEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent> ): void {
sceneryLog && sceneryLog.Input && sceneryLog.Input( `moveEvent ${pointer.toString()}` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
// Always treat move events as "point changed"
- this.branchChangeEvents<DOMEvent>( pointer, event, true );
+ this.branchChangeEvents<DOMEvent>( pointer, context, true );
sceneryLog && sceneryLog.Input && sceneryLog.pop();
}
@@ -1716,21 +1702,20 @@
/**
* Called for each logical "cancel" event, for any pointer type.
*/
- private cancelEvent<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent, point: Vector2 ): void {
-
+ private cancelEvent<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, point: Vector2 ): void {
const pointChanged = pointer.cancel( point );
sceneryLog && sceneryLog.Input && sceneryLog.Input( `cancelEvent ${pointer.toString()} changed:${pointChanged}` );
sceneryLog && sceneryLog.Input && sceneryLog.push();
// We'll use this trail for the entire dispatch of this event.
- const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, event, pointChanged );
+ const eventTrail = this.branchChangeEvents<DOMEvent>( pointer, context, pointChanged );
- this.dispatchEvent<DOMEvent>( eventTrail, 'cancel', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( eventTrail, 'cancel', pointer, context, true );
// touch pointers are transient, so fire exit/out to the trail afterwards
if ( pointer.isTouchLike() ) {
- this.exitEvents<DOMEvent>( pointer, event, eventTrail, 0, true );
+ this.exitEvents<DOMEvent>( pointer, context, eventTrail, 0, true );
}
sceneryLog && sceneryLog.Input && sceneryLog.pop();
@@ -1743,11 +1728,11 @@
* out/over events, and if flagged a move event.
*
* @param pointer
- * @param event
+ * @param context
* @param sendMove - Whether to send move events
* @returns - The current trail of the pointer
*/
- private branchChangeEvents<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent | null, sendMove: boolean ): Trail {
+ private branchChangeEvents<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, sendMove: boolean ): Trail {
sceneryLog && sceneryLog.InputEvent && sceneryLog.InputEvent(
`branchChangeEvents: ${pointer.toString()} sendMove:${sendMove}` );
sceneryLog && sceneryLog.InputEvent && sceneryLog.push();
@@ -1769,12 +1754,12 @@
// event order matches http://www.w3.org/TR/DOM-Level-3-Events/#events-mouseevent-event-order
if ( sendMove ) {
- this.dispatchEvent<DOMEvent>( trail, 'move', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( trail, 'move', pointer, context, true );
}
// We want to approximately mimic http://www.w3.org/TR/DOM-Level-3-Events/#events-mouseevent-event-order
- this.exitEvents<DOMEvent>( pointer, event, oldInputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
- this.enterEvents<DOMEvent>( pointer, event, inputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
+ this.exitEvents<DOMEvent>( pointer, context, oldInputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
+ this.enterEvents<DOMEvent>( pointer, context, inputEnabledTrail, branchInputEnabledIndex, lastInputEnabledNodeChanged );
pointer.trail = trail;
pointer.inputEnabledTrail = inputEnabledTrail;
@@ -1799,13 +1784,13 @@
* for this node and all "descendant" nodes in the relevant trail.
* @param lastNodeChanged - If the last node didn't change, we won't sent an over event.
*/
- private enterEvents<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent | null, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
+ private enterEvents<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
if ( lastNodeChanged ) {
- this.dispatchEvent<DOMEvent>( trail, 'over', pointer, event, true, true );
+ this.dispatchEvent<DOMEvent>( trail, 'over', pointer, context, true, true );
}
for ( let i = branchIndex; i < trail.length; i++ ) {
- this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'enter', pointer, event, false );
+ this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'enter', pointer, context, false );
}
}
@@ -1826,13 +1811,13 @@
* for this node and all "descendant" nodes in the relevant trail.
* @param lastNodeChanged - If the last node didn't change, we won't sent an out event.
*/
- private exitEvents<DOMEvent extends Event>( pointer: Pointer, event: DOMEvent | null, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
+ private exitEvents<DOMEvent extends Event>( pointer: Pointer, context: EventContext<DOMEvent>, trail: Trail, branchIndex: number, lastNodeChanged: boolean ): void {
for ( let i = trail.length - 1; i >= branchIndex; i-- ) {
- this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'exit', pointer, event, false, true );
+ this.dispatchEvent<DOMEvent>( trail.slice( 0, i + 1 ), 'exit', pointer, context, false, true );
}
if ( lastNodeChanged ) {
- this.dispatchEvent<DOMEvent>( trail, 'out', pointer, event, true );
+ this.dispatchEvent<DOMEvent>( trail, 'out', pointer, context, true );
}
}
@@ -1842,11 +1827,11 @@
* @param trail
* @param type
* @param pointer
- * @param event
+ * @param context
* @param bubbles - If bubbles is false, the event is only dispatched to the leaf node of the trail.
* @param fireOnInputDisabled - Whether to fire this event even if nodes have inputEnabled:false
*/
- private dispatchEvent<DOMEvent extends Event>( trail: Trail, type: SupportedEventTypes, pointer: Pointer, event: DOMEvent | null, bubbles: boolean, fireOnInputDisabled = false ): void {
+ private dispatchEvent<DOMEvent extends Event>( trail: Trail, type: SupportedEventTypes, pointer: Pointer, context: EventContext<DOMEvent>, bubbles: boolean, fireOnInputDisabled = false ): void {
sceneryLog && sceneryLog.EventDispatch && sceneryLog.EventDispatch(
`${type} trail:${trail.toString()} pointer:${pointer.toString()} at ${pointer.point ? pointer.point.toString() : 'null'}` );
sceneryLog && sceneryLog.EventDispatch && sceneryLog.push();
@@ -1856,7 +1841,7 @@
sceneryLog && sceneryLog.EventPath && sceneryLog.EventPath( `${type} ${trail.toPathString()}` );
// NOTE: event is not immutable, as its currentTarget changes
- const inputEvent = new SceneryEvent<DOMEvent>( trail, type, pointer, event );
+ const inputEvent = new SceneryEvent<DOMEvent>( trail, type, pointer, context );
// first run through the pointer's listeners to see if one of them will handle the event
this.dispatchToListeners<DOMEvent>( pointer, pointer.getListeners(), type, inputEvent );
Index: sun/js/ComboBox.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/ComboBox.ts b/sun/js/ComboBox.ts
--- a/sun/js/ComboBox.ts (revision 6927a8201090c6b6800b8a142740c9ca16029055)
+++ b/sun/js/ComboBox.ts (date 1682530318071)
@@ -354,7 +354,11 @@
// Clicking on the button toggles visibility of the list box
this.button.addListener( () => {
this.listBox.visibleProperty.value = !this.listBox.visibleProperty.value;
- this.listBox.visibleProperty.value && this.listBox.focus();
+ // this.listBox.visibleProperty.value && this.listBox.focus();
+
+ const listItemNode = this.listBox.getListItemNode( property.value );
+ listItemNode.supplyOpenResponseOnNextFocus();
+ listItemNode.focus();
} );
this.display = null;
Index: scenery/js/accessibility/pdom/PDOMTree.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/pdom/PDOMTree.js b/scenery/js/accessibility/pdom/PDOMTree.js
--- a/scenery/js/accessibility/pdom/PDOMTree.js (revision bc5f70afab1993ded43cf4bc694b743f065a1278)
+++ b/scenery/js/accessibility/pdom/PDOMTree.js (date 1682537770049)
@@ -7,10 +7,10 @@
*/
import arrayDifference from '../../../../phet-core/js/arrayDifference.js';
-import { FocusManager, Node, PartialPDOMTrail, PDOMInstance, scenery, Trail } from '../../imports.js';
+import { BrowserEvents, Node, PartialPDOMTrail, PDOMInstance, scenery, Trail } from '../../imports.js';
-// globals (for restoring focus)
-let focusedNode = null;
+// Reference to the focused DOM element, so we can restore focus between big tree operations.
+let activeElementId = null;
const PDOMTree = {
/**
@@ -28,13 +28,13 @@
assert && assert( child instanceof Node );
assert && assert( !child._rendererSummary.hasNoPDOM() );
- const blockedDisplays = PDOMTree.beforeOp( child );
+ PDOMTree.beforeOp();
if ( !child._pdomParent ) {
PDOMTree.addTree( parent, child );
}
- PDOMTree.afterOp( blockedDisplays );
+ PDOMTree.afterOp();
sceneryLog && sceneryLog.PDOMTree && sceneryLog.pop();
},
@@ -54,13 +54,13 @@
assert && assert( child instanceof Node );
assert && assert( !child._rendererSummary.hasNoPDOM() );
- const blockedDisplays = PDOMTree.beforeOp( child );
+ PDOMTree.beforeOp();
if ( !child._pdomParent ) {
PDOMTree.removeTree( parent, child );
}
- PDOMTree.afterOp( blockedDisplays );
+ PDOMTree.afterOp();
sceneryLog && sceneryLog.PDOMTree && sceneryLog.pop();
},
@@ -78,11 +78,11 @@
assert && assert( node instanceof Node );
assert && assert( !node._rendererSummary.hasNoPDOM() );
- const blockedDisplays = PDOMTree.beforeOp( node );
+ PDOMTree.beforeOp();
PDOMTree.reorder( node );
- PDOMTree.afterOp( blockedDisplays );
+ PDOMTree.afterOp();
sceneryLog && sceneryLog.PDOMTree && sceneryLog.pop();
},
@@ -101,7 +101,7 @@
assert && assert( node instanceof Node );
- const blockedDisplays = PDOMTree.beforeOp( node );
+ PDOMTree.beforeOp();
const removedItems = []; // {Array.<Node|null>} - May contain the placeholder null
const addedItems = []; // {Array.<Node|null>} - May contain the placeholder null
@@ -173,7 +173,7 @@
PDOMTree.reorder( node, pdomTrails );
- PDOMTree.afterOp( blockedDisplays );
+ PDOMTree.afterOp();
sceneryLog && sceneryLog.PDOMTree && sceneryLog.pop();
},
@@ -190,7 +190,7 @@
assert && assert( node instanceof Node );
- const blockedDisplays = PDOMTree.beforeOp( node );
+ PDOMTree.beforeOp();
let i;
const parents = node._pdomParent ? [ node._pdomParent ] : node._parents;
@@ -220,7 +220,7 @@
}
}
- PDOMTree.afterOp( blockedDisplays );
+ PDOMTree.afterOp();
sceneryLog && sceneryLog.PDOMTree && sceneryLog.pop();
},
@@ -390,37 +390,20 @@
* Prepares for an pdom-tree-changing operation (saving some state). During DOM operations we don't want Display
* input to dispatch events as focus changes.
* @private
- *
- * @param {Node} node - root of Node subtree whose PDOMInstance tree is being rearranged.
*/
- beforeOp( node ) {
- focusedNode = FocusManager.pdomFocusedNode;
-
- // list of displays to stop blocking focus callbacks in afterOp
- const displays = [];
-
- const pdomTrails = this.findPDOMTrails( node );
- for ( let i = 0; i < pdomTrails.length; i++ ) {
- const display = pdomTrails[ i ].pdomInstance.display;
- display.blockFocusCallbacks = true;
- displays.push( display );
- }
-
- return displays;
+ beforeOp() {
+ activeElementId = document.activeElement.id;
+ BrowserEvents.blockFocusCallbacks = true;
},
/**
* Finalizes an pdom-tree-changing operation (restoring some state).
* @private
- *
- * @param {Array.<Display>} blockedDisplays
*/
- afterOp( blockedDisplays ) {
- focusedNode && focusedNode.focus();
-
- for ( let i = 0; i < blockedDisplays.length; i++ ) {
- blockedDisplays[ i ].blockFocusCallbacks = false;
- }
+ afterOp() {
+ const activeElement = document.getElementById( activeElementId );
+ activeElement && activeElement.focus();
+ BrowserEvents.blockFocusCallbacks = false;
},
/**
Index: sun/js/ComboBoxListBox.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/ComboBoxListBox.ts b/sun/js/ComboBoxListBox.ts
--- a/sun/js/ComboBoxListBox.ts (revision 6927a8201090c6b6800b8a142740c9ca16029055)
+++ b/sun/js/ComboBoxListBox.ts (date 1682531583759)
@@ -222,13 +222,13 @@
this.addInputListener( {
// When the list box gets focus, transfer focus to the ComboBoxListItemNode that matches property.value.
- focus: () => {
- if ( this.visible ) {
- const listItemNode = this.getListItemNode( property.value );
- listItemNode.supplyOpenResponseOnNextFocus();
- listItemNode.focus();
- }
- },
+ // focus: () => {
+ // if ( this.visible ) {
+ // const listItemNode = this.getListItemNode( property.value );
+ // listItemNode.supplyOpenResponseOnNextFocus();
+ // listItemNode.focus();
+ // }
+ // },
// Handle keydown
keydown: event => {
Index: scenery/js/input/EventContext.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/EventContext.ts b/scenery/js/input/EventContext.ts
new file mode 100644
--- /dev/null (date 1682524998267)
+++ b/scenery/js/input/EventContext.ts (date 1682524998267)
@@ -0,0 +1,53 @@
+// Copyright 2023, University of Colorado Boulder
+
+/**
+ * A collection of information about an event and the environment when it was fired
+ *
+ * @author Jonathan Olson <[email protected]>
+ */
+
+import IOType from '../../../tandem/js/types/IOType.js';
+import { scenery, EventIO, Input } from '../imports.js';
+
+export default class EventContext<out DOMEvent extends Event = Event> {
+
+ // Raw DOM InputEvent (TouchEvent, PointerEvent, MouseEvent,...)
+ public readonly domEvent: DOMEvent;
+
+ // The document.activeElement when the event was fired
+ public readonly activeElement: Element | null;
+
+ public constructor( domEvent: DOMEvent ) {
+ this.domEvent = domEvent;
+ this.activeElement = document.activeElement;
+ }
+
+ public static createSynthetic(): EventContext {
+ return new EventContext( new window.Event( 'synthetic' ) );
+ }
+}
+
+export const EventContextIO = new IOType( 'EventContextIO', {
+ valueType: EventContext,
+ documentation: 'A DOM event and its context',
+ toStateObject: eventContext => {
+ return {
+ domEvent: Input.serializeDomEvent( eventContext.domEvent )
+
+ // Ignores the activeElement, since we don't have a good way of serializing that at this point?
+ };
+ },
+ fromStateObject: stateObject => {
+ return new EventContext( Input.deserializeDomEvent( stateObject.domEvent ) );
+ },
+
+ // This should remain the same as Input.domEventPropertiesToSerialize (local var). Each key can be null depending on
+ // what Event interface is being serialized (which depends on what DOM Event the instance is).
+ stateSchema: () => ( {
+ domEvent: EventIO
+
+ // Ignores the activeElement, since we don't have a good way of serializing that at this point?
+ } )
+} );
+
+scenery.register( 'EventContext', EventContext );
|
… (details below) 1. PDOMTree before/after op uses all Displays, and moves blockFocusCallbacks from Display to BrowserEvents (to catch before batching) 2. Adds EventContext, replaced with Event in many cases, so we can store activeElement (or other future things) from when the event fired 3. Adds a better way of synthesizing fake events (EventContext.createSynthetic()), so that we don't need conditionals on events. Pointer.lastEventContext should be guaranteed once it's set up once. 4. Adds activeElement to SceneryEvent 5. ComboBox ListBox selection doesn't rely on seeing if the box gets focus. We directly focus the item instead instead of the redirection 6. Regenerated phet-io APIs
1. PDOMTree before/after op uses all Displays, and moves blockFocusCallbacks from Display to BrowserEvents (to catch before batching) 2. Adds EventContext, replaced with Event in many cases, so we can store activeElement (or other future things) from when the event fired 3. Adds a better way of synthesizing fake events (EventContext.createSynthetic()), so that we don't need conditionals on events. Pointer.lastEventContext should be guaranteed once it's set up once. 4. Adds activeElement to SceneryEvent 5. ComboBox ListBox selection doesn't rely on seeing if the box gets focus. We directly focus the item instead instead of the redirection 6. Regenerated phet-io APIs
Phet-io looks good (didn't break mirror input wrapper). I did some additional cleanup (note the ComboBox changes). @jessegreenberg can you verify on your end, I think this should be handled? |
Awesome, thanks! Thanks for re-generating APIs. The commit message is great. Changes to ComboBox look coorect to me. I verified behavior in master once more in a few sims as well as unit tests. Ready to close. |
Just a tiny update here. . . In firefox I am getting this warning about 400 times while loading on fuzz:
So with the above commit, I'm silencing them. Shouldn't cause any trouble, but feel free to reopen. |
OK, thanks @zepumph that looks good. |
The beforeOp/afterOp change is causing an issue in the case of the focused Node having its trail change during a PDOMTree operation. Around here: scenery/js/accessibility/pdom/PDOMTree.js Lines 394 to 397 in 9715e02
The document.activeElement.id is from the Node's PartialPDOMTrail before the reorder operation. After the PDOM reorder, the trail changes and it is impossible to restore focus to the element in the afterOp. I am trying to make unit tests for this case but haven't recreated the problem yet. |
Reverting the workaround of phetsims/center-and-variability#162 I am not seeing a change in trail in the unique ID, so its possible that my assessment is not correct. Logging unique ID of focused Node trail before and after operations: EDIT: Actually, this shows that my theory is correct FocusManager state is correct, but the activeElementId is stale. The fact that the trail didn't change in my first test tells me that the activeElementID is already wrong before the beforeOp. Reverting changes in beforeOp and afterOp so that it puts focus on the Node (with accurate trails) instead of using document.activeElement fixes CAV but reintroduces phetsims/my-solar-system#157. |
Notes from investigation today:
const a1 = new Node( { tagName: 'div' } );
const b1 = new Node( { tagName: 'button', focusable: true } );
const c1 = new Node( { tagName: 'div', focusable: true } );
const d1 = new Node( { tagName: 'div', focusable: true } );
const d2 = new Node( { tagName: 'div', focusable: true } );
rootNode.addChild( a1 );
a1.children = [ b1, c1 ];
b1.children = [ d1 ];
b1.addInputListener( {
click: event => {
// focus something, triggering reentrant events under the `click` event.
d1.focus();
// FocusManager.pdomFocusedNode is NOT d1!! The focus event is reentrant and so PDOMPointer listeners won't run until
// later.
// d1.focused is FALSE!! Because FocusManager is not correct
// Meanwhile, document.activeElement is the primary sibling of d1 (correct).
// change the trail to the Node - this will cause focus on d1 to be lost, and PDOMTree will
// be unable to restore it.
a1.pdomOrder = [ d1, d2, null ];
// verify that focus is restored - even if it IS restored, d1.focused will return false because
// FocusManater.pdomFocus is stale!
assert.ok( d1.focused, 'd1 should still trail change operations in reentrant events' );
}
} );
b1.focus();
b1.pdomInstances[ 0 ].peer!.primarySibling!.click(); We need to watch focus synchronously without batching. Either we need some new field on FocusManager or FocusManager.pdomFocus needs to be udpated so that it changes without batching. |
This patch works in CAV, BASE, and MSS. But some unit tests are failing. Its also a pretty disruptive change. I want to consider the changes to PDOMPointer in particular, while this change makes sense to my understanding it removes some complicated code that is probably necessary. Subject: [PATCH] Use Checkbox directly, remove superclass, see https://github.com/phetsims/gravity-force-lab-basics/issues/324"
---
Index: scenery/js/input/PDOMPointer.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/PDOMPointer.ts b/scenery/js/input/PDOMPointer.ts
--- a/scenery/js/input/PDOMPointer.ts (revision 1c92a8edacb73c3c7244e2a0f315be4b2d37029f)
+++ b/scenery/js/input/PDOMPointer.ts (date 1686783620537)
@@ -56,8 +56,6 @@
// NOTE: The "root" peer can't be focused (so it doesn't matter if it doesn't have a node).
if ( lastNode.focusable ) {
const visualTrail = PDOMInstance.guessVisualTrail( this.trail!, this.display.rootNode );
-
- FocusManager.pdomFocus = new Focus( this.display, visualTrail );
this.point = visualTrail.parentToGlobalPoint( lastNode.center );
// TODO: it would be better if we could use this assertion instead, but guessVisualTrail seems to not be working here, https://github.com/phetsims/phet-io/issues/1847
@@ -72,30 +70,30 @@
// before we receive the `focus` event. In that case, the browser will still try to put focus on the element
// even though the PDOM element and Node are not in the traversal order. It is more consistent to remove
// focus in this case.
- event.target.blur();
+ // event.target.blur();
// do not allow any more focus listeners to dispatch, this Node should never have been focused in the
// first place, but the browser did it anyway
- event.abort();
+ // event.abort();
}
},
blur: event => {
assert && assert( event.domEvent );
// Null if it is not in the PDOM, or if it is undefined
- const relatedTargetTrail = this.display._input!.getRelatedTargetTrail( event.domEvent! );
+ // const relatedTargetTrail = this.display._input!.getRelatedTargetTrail( event.domEvent! );
this.trail = null;
- if ( relatedTargetTrail && relatedTargetTrail.lastNode().focusable ) {
- FocusManager.pdomFocus = new Focus( this.display, PDOMInstance.guessVisualTrail( relatedTargetTrail, this.display.rootNode ) );
- }
- else {
-
- // Don't set this before the related target case because we want to support Node.blur listeners overwriting
- // the relatedTarget behavior.
- FocusManager.pdomFocus = null;
- }
+ // if ( relatedTargetTrail && relatedTargetTrail.lastNode().focusable ) {
+ // FocusManager.pdomFocus = new Focus( this.display, PDOMInstance.guessVisualTrail( relatedTargetTrail, this.display.rootNode ) );
+ // }
+ // else {
+ //
+ // // Don't set this before the related target case because we want to support Node.blur listeners overwriting
+ // // the relatedTarget behavior.
+ // FocusManager.pdomFocus = null;
+ // }
this.keydownTargetNode = null;
},
Index: scenery/js/accessibility/pdom/PDOMTree.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/pdom/PDOMTree.js b/scenery/js/accessibility/pdom/PDOMTree.js
--- a/scenery/js/accessibility/pdom/PDOMTree.js (revision 1c92a8edacb73c3c7244e2a0f315be4b2d37029f)
+++ b/scenery/js/accessibility/pdom/PDOMTree.js (date 1686784129229)
@@ -7,10 +7,10 @@
*/
import arrayDifference from '../../../../phet-core/js/arrayDifference.js';
-import { BrowserEvents, Node, PartialPDOMTrail, PDOMInstance, scenery, Trail } from '../../imports.js';
+import { BrowserEvents, FocusManager, Node, PartialPDOMTrail, PDOMInstance, scenery, Trail } from '../../imports.js';
// Reference to the focused DOM element, so we can restore focus between big tree operations.
-let activeElementId = null;
+let focusedNode = null;
const PDOMTree = {
/**
@@ -392,7 +392,7 @@
* @private
*/
beforeOp() {
- activeElementId = document.activeElement.id;
+ focusedNode = FocusManager.pdomFocusedNode;
BrowserEvents.blockFocusCallbacks = true;
},
@@ -401,9 +401,8 @@
* @private
*/
afterOp() {
- if ( activeElementId ) {
- const activeElement = document.getElementById( activeElementId );
- activeElement && activeElement.focus();
+ if ( focusedNode && focusedNode.focusable ) {
+ focusedNode.focus();
}
BrowserEvents.blockFocusCallbacks = false;
},
Index: scenery/js/input/BrowserEvents.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/input/BrowserEvents.js b/scenery/js/input/BrowserEvents.js
--- a/scenery/js/input/BrowserEvents.js (revision 1c92a8edacb73c3c7244e2a0f315be4b2d37029f)
+++ b/scenery/js/input/BrowserEvents.js (date 1686783636827)
@@ -763,9 +763,8 @@
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
- // if ( domEvent.target.id === 'display1-primary-30-44-2795-2802-2797-2806-3012-3011-2992' ) {
- // debugger;
- // }
+ // Update synchronous
+ FocusManager.updatePDOMFocusSynchronous( BrowserEvents.attachedDisplays );
BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'focusIn', true );
@@ -777,6 +776,9 @@
sceneryLog && sceneryLog.OnInput && sceneryLog.push();
// NOTE: Will be called without a proper 'this' reference. Do NOT rely on it here.
+
+ FocusManager.pdomFocus = null;
+
BrowserEvents.batchWindowEvent( new EventContext( domEvent ), BatchedDOMEventType.ALT_TYPE, 'focusOut', true );
sceneryLog && sceneryLog.OnInput && sceneryLog.pop();
Index: scenery/js/accessibility/FocusTests.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/FocusTests.ts b/scenery/js/accessibility/FocusTests.ts
--- a/scenery/js/accessibility/FocusTests.ts (revision 1c92a8edacb73c3c7244e2a0f315be4b2d37029f)
+++ b/scenery/js/accessibility/FocusTests.ts (date 1686783693681)
@@ -418,10 +418,59 @@
b1.pdomOrder = [ d3, d4 ];
assert.ok( d1.focused, 'd1 should still have focus after order change' );
-
b1.pdomOrder = null;
+
c1.pdomOrder = [ d4, d3, d2, d1 ];
assert.ok( d1.focused, 'd1 should still have focus after order change' );
+ c1.pdomOrder = null;
+
+ a1.pdomOrder = [ d1, d2, d3 ];
+ assert.ok( d1.focused, 'd1 should still have focus after order change' );
+
+ display.detachEvents();
+} );
+
+QUnit.test( 'pdomOrder with reentrant events', assert => {
+ if ( !document.hasFocus() ) {
+ assert.ok( true, 'Opting out of test because document does not have focus' );
+ return;
+ }
+
+ const rootNode = new Node();
+ const display = new Display( rootNode );
+ display.initializeEvents();
+ document.body.appendChild( display.domElement );
+
+ const a1 = new Node( { tagName: 'div' } );
+ const b1 = new Node( { tagName: 'button', focusable: true } );
+ const c1 = new Node( { tagName: 'div', focusable: true } );
+ const d1 = new Node( { tagName: 'div', focusable: true } );
+ const d2 = new Node( { tagName: 'div', focusable: true } );
+
+ rootNode.addChild( a1 );
+ a1.children = [ b1, c1 ];
+ b1.children = [ d1 ];
+
+ b1.addInputListener( {
+ click: event => {
+
+ // focus another thing
+ d1.focus();
+
+ // FocusManager.pdomFocusedNode is NOT d1!! because the focus event to update
+ // FocusManager is reentrant from click
+
+ // change the trail to the Node
+ a1.pdomOrder = [ d1, d2, null ];
+
+ // verify that focus is restored
+ assert.ok( d1.focused, 'd1 should still trail change operations in reentrant events' );
+ }
+ } );
+
+ b1.focus();
+ b1.pdomInstances[ 0 ].peer!.primarySibling!.click();
+ assert.ok( true, 'dummy test that should fire after click events' );
display.detachEvents();
} );
Index: center-and-variability/js/soccer-common/view/SoccerSceneView.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/center-and-variability/js/soccer-common/view/SoccerSceneView.ts b/center-and-variability/js/soccer-common/view/SoccerSceneView.ts
--- a/center-and-variability/js/soccer-common/view/SoccerSceneView.ts (revision a152fe0414421c0d6b8edcb5161ca09094fb50fa)
+++ b/center-and-variability/js/soccer-common/view/SoccerSceneView.ts (date 1686783819113)
@@ -132,7 +132,7 @@
soccerBallNode.focusable = i === stack.length - 1;
// Focus order goes left to right
- backLayerSoccerBallLayer.setPDOMOrder( sceneModel.getTopSoccerBalls().map( soccerBall => soccerBallMap.get( soccerBall )! ) );
+ frontLayer.setPDOMOrder( sceneModel.getTopSoccerBalls().map( soccerBall => soccerBallMap.get( soccerBall )! ) );
}
} );
Index: scenery/js/accessibility/FocusManager.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/FocusManager.ts b/scenery/js/accessibility/FocusManager.ts
--- a/scenery/js/accessibility/FocusManager.ts (revision 1c92a8edacb73c3c7244e2a0f315be4b2d37029f)
+++ b/scenery/js/accessibility/FocusManager.ts (date 1686784306751)
@@ -33,7 +33,7 @@
import Tandem from '../../../tandem/js/Tandem.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import Utterance from '../../../utterance-queue/js/Utterance.js';
-import { Focus, FocusDisplayedController, Node, ReadingBlockUtterance, scenery, voicingManager } from '../imports.js';
+import { Display, Focus, FocusDisplayedController, Node, PDOMInstance, PDOMUtils, ReadingBlockUtterance, scenery, voicingManager } from '../imports.js';
type SpeakingListener = ( text: string, utterance: Utterance ) => void;
@@ -168,6 +168,32 @@
voicingManager.voicingFullyEnabledProperty.unlink( this.voicingFullyEnabledListener );
}
+ /**
+ * Update the pdomFocus from an immediate event. Scenery events are batched so that they cannot be
+ * reentrant. Listeners that are batched should have an accurate representation of what
+ * currently has focus, and that information comes directly from the DOM.
+ *
+ * @param displays - List of any displays that are attached to BrowserEvents.
+ */
+ public static updatePDOMFocusSynchronous( displays: Display[] ): void {
+ assert && assert( document.activeElement, 'Must be called from focusin, therefore active elemetn expected' );
+
+ const uniqueId = document.activeElement!.getAttribute( PDOMUtils.DATA_PDOM_UNIQUE_ID )!;
+ assert && assert( uniqueId, 'Event target must have a unique ID on its data' );
+
+ for ( let i = 0; i < displays.length; i++ ) {
+ const display = displays[ i ];
+ const trail = PDOMInstance.uniqueIdToTrail( display, uniqueId );
+ if ( trail ) {
+ const visualTrail = PDOMInstance.guessVisualTrail( trail, display.rootNode );
+ FocusManager.pdomFocus = new Focus( display, visualTrail );
+
+ // no need to keep searching
+ break;
+ }
+ }
+ }
+
/**
* Set the DOM focus. A DOM limitation is that there can only be one element with focus at a time so this must
* be a static for the FocusManager.
@@ -226,7 +252,6 @@
phetioReadOnly: true
} );
-
/**
* A Property that lets you know when the window has focus. When the window has focus, it is in the user's foreground.
* When in the background, the window does not receive keyboard input (important for global keyboard events).
|
Hydrogen MR has applied this to these sims:
Next we are ready for testing. |
For QA: |
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#864, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#864, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965
This was confirmed fixed by QA for all MR sims with a Combo Box. Closing |
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#864, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#864, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
…o#1974, getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
… getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#864, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
… getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
… getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
… getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
… getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#864, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
… getPhetioOverridesFile, phetsims/phet-io#1974, createFromStandardPhetioWrapper: phetsims/phet-io#1974, getDOMElementID: phetsims/phet-io#1974, SIMULATION_VERSION_STRING: phetsims/phet-io#1974, SIMULATION_VERSION_MAJOR_MINOR_STRING1: phetsims/phet-io#1974, unlinkIndex: phetsims/phet-io#1974, getSimulationURL: phetsims/phet-io#1974, addSimulationInitializedListener: phetsims/phet-io#1974, launchSimulation: phetsims/phet-io#1974, displaySimulation: phetsims/phet-io#1974, setSimulationStartedMetadata: phetsims/phet-io#1974, clientGuide: phetsims/phet-io#1974, getPhetioElementState: phetsims/phet-io#1974, keyboardTraversal: phetsims/sun#859, phetsims/scenery#1550, phetsims/sun#861, phetsims/sun#862, phetioClientRename: phetsims/phet-io#1965, phetsims/studio#317
There are problems with reentrant focus/blur events. Today @jonathanolson @samreid and @jessegreenberg looked into phetsims/my-solar-system#142 - a
click
event has listeners that cause a PDOM reorder involving the focused element. This triggers reentrant events forfocus
andblur
that get batched later and focus gets lost from the page.The batched
blur
listener triggers a manualelement.blur
(in PDOMPointer), and then the batchedfocus
listener fails to work correctly because there is no focused element in the DOM.We looked into a couple of solutions:
element.focus()
in this function:https://github.com/phetsims/scenery/blob/f563cec0342d1a3d147a9402d72bcaffb37dfdce/js/accessibility/FocusManager.ts#L175-L190
. This caused an infinite function loop, and we didn't investigate further.For now, we made it so that the reorder in PDOMInstance does not remove an element with focus. Elements are ordered around the focused DOM element so that focus is not lost from the DOM.
This is a good change that will work for the case of my-solar-system, but may not work for all DOM tree operations. We want to handle the reentrant event issue more generally.
The text was updated successfully, but these errors were encountered: