Index: sun/js/Checkbox.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/Checkbox.js b/sun/js/Checkbox.js
--- a/sun/js/Checkbox.js (revision 0c107a2323019ce22ab6510d7f914e2acc5355f1)
+++ b/sun/js/Checkbox.js (date 1643061986302)
@@ -34,7 +34,7 @@
const uncheckedShape = checkEmptySolidShape.transformed( SHAPE_MATRIX );
const checkedShape = checkSquareOSolidShape.transformed( SHAPE_MATRIX );
-class Checkbox extends Node {
+class Checkbox extends Voicing( Node ) {
/**
* @param {Node} content
@@ -88,9 +88,6 @@
super();
- // voicing - initialize the Trait
- this.initializeVoicing();
-
// @private - sends out notifications when the checkbox is toggled.
const toggleAction = new Action( () => {
property.value = !property.value;
@@ -240,7 +237,5 @@
get checkboxColor() { return this.getCheckboxColor(); }
}
-Voicing.compose( Checkbox );
-
sun.register( 'Checkbox', Checkbox );
export default Checkbox;
\ No newline at end of file
Index: sun/js/accessibility/AccessibleValueHandler.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/accessibility/AccessibleValueHandler.js b/sun/js/accessibility/AccessibleValueHandler.js
--- a/sun/js/accessibility/AccessibleValueHandler.js (revision 0c107a2323019ce22ab6510d7f914e2acc5355f1)
+++ b/sun/js/accessibility/AccessibleValueHandler.js (date 1643062538085)
@@ -46,7 +46,8 @@
const proto = type.prototype;
// compose with Interactive Highlights, all Nodes with Voicing features highlight as they are interactive
- Voicing.compose( type );
+ // TODO: handle this case, https://github.com/phetsims/scenery/issues/1340
+ // Voicing.compose( type );
extend( proto, {
@@ -216,7 +217,7 @@
optionsToMutate.inputType = 'range';
// Should occur before mutate to support mutating Voicing options.
- this.initializeVoicing();
+ // this.initializeVoicing();
this.mutate( optionsToMutate );
Index: ratio-and-proportion/js/common/view/RatioHandNode.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ratio-and-proportion/js/common/view/RatioHandNode.ts b/ratio-and-proportion/js/common/view/RatioHandNode.ts
--- a/ratio-and-proportion/js/common/view/RatioHandNode.ts (revision 4a0bd79b66243fc1158eaa39402432812938e738)
+++ b/ratio-and-proportion/js/common/view/RatioHandNode.ts (date 1643064704511)
@@ -16,7 +16,7 @@
import ArrowNode from '../../../../scenery-phet/js/ArrowNode.js';
import ArrowKeyNode from '../../../../scenery-phet/js/keyboard/ArrowKeyNode.js';
import LetterKeyNode from '../../../../scenery-phet/js/keyboard/LetterKeyNode.js';
-import { Color, FocusHighlightFromNode, Node, NodeOptions, Path, PathOptions } from '../../../../scenery/js/imports.js';
+import { Color, FocusHighlightFromNode, Node, NodeOptions, Path, PathOptions, Voicing } from '../../../../scenery/js/imports.js';
import AccessibleSlider from '../../../../sun/js/accessibility/AccessibleSlider.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import ratioAndProportion from '../../ratioAndProportion.js';
@@ -36,7 +36,7 @@
handNodeOptions?: NodeOptions
};
-class RatioHandNode extends Node {
+class RatioHandNode extends Voicing( Node ) {
private resetRatioHandNode: () => void;
/**
Index: sun/js/ToggleSwitch.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/ToggleSwitch.js b/sun/js/ToggleSwitch.js
--- a/sun/js/ToggleSwitch.js (revision 0c107a2323019ce22ab6510d7f914e2acc5355f1)
+++ b/sun/js/ToggleSwitch.js (date 1643062136891)
@@ -29,7 +29,7 @@
// constants
const DEFAULT_SIZE = new Dimension2( 60, 30 );
-class ToggleSwitch extends Node {
+class ToggleSwitch extends Voicing( Node ) {
/**
* @param {Property.<*>} property
@@ -102,8 +102,6 @@
super();
- this.initializeVoicing();
-
const cornerRadius = options.size.height / 2;
// track that the thumb slides in
@@ -271,7 +269,5 @@
}
}
-Voicing.compose( ToggleSwitch );
-
sun.register( 'ToggleSwitch', ToggleSwitch );
export default ToggleSwitch;
\ No newline at end of file
Index: sun/js/AquaRadioButton.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/AquaRadioButton.js b/sun/js/AquaRadioButton.js
--- a/sun/js/AquaRadioButton.js (revision 0c107a2323019ce22ab6510d7f914e2acc5355f1)
+++ b/sun/js/AquaRadioButton.js (date 1643061986244)
@@ -21,7 +21,7 @@
// constants
const DEFAULT_RADIUS = 7;
-class AquaRadioButton extends Node {
+class AquaRadioButton extends Voicing( Node ) {
/**
* @mixes {Voicing}
@@ -72,9 +72,6 @@
super();
- // voicing - initialize the trait
- this.initializeVoicing();
-
// @public (read-only)
this.value = value;
@@ -183,7 +180,5 @@
AquaRadioButton.DEFAULT_RADIUS = DEFAULT_RADIUS;
-Voicing.compose( AquaRadioButton );
-
sun.register( 'AquaRadioButton', AquaRadioButton );
export default AquaRadioButton;
\ No newline at end of file
Index: sun/js/ComboBoxListItemNode.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sun/js/ComboBoxListItemNode.js b/sun/js/ComboBoxListItemNode.js
--- a/sun/js/ComboBoxListItemNode.js (revision 0c107a2323019ce22ab6510d7f914e2acc5355f1)
+++ b/sun/js/ComboBoxListItemNode.js (date 1643062136870)
@@ -18,7 +18,7 @@
import ComboBoxItem from './ComboBoxItem.js';
import sun from './sun.js';
-class ComboBoxListItemNode extends Node {
+class ComboBoxListItemNode extends Voicing( Node ) {
/**
* @param {ComboBoxItem} item
@@ -98,9 +98,6 @@
super();
- // voicing - initialize the Voicing trait
- this.initializeVoicing();
-
// @public (read-only)
this.item = item;
@@ -120,7 +117,5 @@
}
}
-Voicing.compose( ComboBoxListItemNode );
-
sun.register( 'ComboBoxListItemNode', ComboBoxListItemNode );
export default ComboBoxListItemNode;
\ No newline at end of file
Index: scenery/js/accessibility/voicing/Voicing.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/voicing/Voicing.ts b/scenery/js/accessibility/voicing/Voicing.ts
--- a/scenery/js/accessibility/voicing/Voicing.ts (revision faa4e9d6dbd874a6d3bd9a0b6dd4acabb54651b9)
+++ b/scenery/js/accessibility/voicing/Voicing.ts (date 1643070692205)
@@ -23,13 +23,14 @@
* @author Jesse Greenberg (PhET Interactive Simulations)
*/
-import extend from '../../../../phet-core/js/extend.js';
import inheritance from '../../../../phet-core/js/inheritance.js';
-import merge from '../../../../phet-core/js/merge.js';
import responseCollector from '../../../../utterance-queue/js/responseCollector.js';
-import ResponsePacket from '../../../../utterance-queue/js/ResponsePacket.js';
+import ResponsePacket, { ResponsePacketOptions } from '../../../../utterance-queue/js/ResponsePacket.js';
import ResponsePatternCollection from '../../../../utterance-queue/js/ResponsePatternCollection.js';
-import { InteractiveHighlighting, Node, scenery, voicingUtteranceQueue } from '../../imports.js';
+import Utterance from '../../../../utterance-queue/js/Utterance.js';
+import UtteranceQueue from '../../../../utterance-queue/js/UtteranceQueue.js';
+import { InteractiveHighlighting, Node, scenery, SceneryEvent, voicingUtteranceQueue } from '../../imports.js';
+import optionize from '../../../../phet-core/js/optionize.js';
// options that are supported by Voicing.js. Added to mutator keys so that Voicing properties can be set with mutate.
const VOICING_OPTION_KEYS = [
@@ -43,462 +44,414 @@
'voicingFocusListener'
];
-const Voicing = {
+type Constructor = new ( ...args: any[] ) => T;
- /**
- * @public
- * @trait {Node}
- * @mixes {InteractiveHighlighting}
- * @param {function(new:Node)} type - The type (constructor) whose prototype that is modified. Should be a Node class.
- */
- compose( type ) {
- assert && assert( _.includes( inheritance( type ), Node ), 'Only Node subtypes should compose Voicing' );
+type ResponseOptions = {
+ utterance?: Utterance | null;
+} & ResponsePacketOptions;
- const proto = type.prototype;
- // compose with Interactive Highlights, all Nodes with Voicing features highlight as they are interactive
- InteractiveHighlighting.compose( type );
-
- extend( proto, {
+type SceneryListener = ( event: SceneryEvent ) => void;
- /**
- * {Array.} - String keys for all of the allowed options that will be set by node.mutate( options ), in
- * the order they will be evaluated.
- * @protected
- *
- * NOTE: See Node's _mutatorKeys documentation for more information on how this operates, and potential special
- * cases that may apply.
- */
- _mutatorKeys: VOICING_OPTION_KEYS.concat( proto._mutatorKeys ),
+/**
+ * @param {function(new:Node)} Type
+ * @returns {function(new:Node)}
+ */
+const Voicing = ( Type: Constructor ) => {
+
+ assert && assert( _.includes( inheritance( Type ), Node ), 'Only Node subtypes should compose Voicing' );
+
- /**
- * Initialize in the type being composed with Voicing. Call this in the constructor. Note, this must be called before
- * options are mutated, so most often you must call options via `mutate()` instead of passing directly to `super()`.
- * @public
- */
- initializeVoicing() {
+ /**
+ * @extends Node
+ * @mixes InteractiveHighlighting
+ */
+ const X = class extends Type {
+ private voicingResponsePacket: ResponsePacket;
+ private _voicingUtteranceQueue: UtteranceQueue | null;
+ private _voicingFocusListener: SceneryListener;
+ private speakContentOnFocusListener: { focus: SceneryListener };
- // undefined OR support poolable with the value set by dispose
- assert && assert( this.voicingInitialized === undefined || this.voicingInitialized === false, 'Voicing has already been initialized for this Node' );
+ constructor( ...args: any[] ) {
+ super( ...args );
- // initialize "super" Trait to support highlights on mouse input
- this.initializeInteractiveHighlighting();
+ // initialize "super" Trait to support highlights on mouse input
+ // TODO: Fix this, https://github.com/phetsims/scenery/issues/1340
+ // @ts-ignore
+ this.initializeInteractiveHighlighting();
- // @private {boolean} - to make sure that initializeVoicing is called before trying to use the mixin.
- this.voicingInitialized = true;
-
- // @public {ResponsePacket} - ResponsePacket that holds all the supported responses to be Voiced
- this.voicingResponsePacket = new ResponsePacket();
+ // @public {ResponsePacket} - ResponsePacket that holds all the supported responses to be Voiced
+ this.voicingResponsePacket = new ResponsePacket();
- // @private {UtteranceQueue|null} - The utteranceQueue that responses for this Node will be spoken through.
- // By default (null), it will go through the singleton voicingUtteranceQueue, but you may need separate
- // UtteranceQueues for different areas of content in your application. For example, Voicing and
- // the default voicingUtteranceQueue may be disabled, but you could still want some speech to come through
- // while user is changing preferences or other settings.
- this._voicingUtteranceQueue = null;
+ // @private {UtteranceQueue|null} - The utteranceQueue that responses for this Node will be spoken through.
+ // By default (null), it will go through the singleton voicingUtteranceQueue, but you may need separate
+ // UtteranceQueues for different areas of content in your application. For example, Voicing and
+ // the default voicingUtteranceQueue may be disabled, but you could still want some speech to come through
+ // while user is changing preferences or other settings.
+ this._voicingUtteranceQueue = null;
- // @private {Function(event):} - called when this node is focused.
- this._voicingFocusListener = this.defaultFocusListener;
+ // @private {Function(event):} - called when this node is focused.
+ this._voicingFocusListener = this.defaultFocusListener;
- // @private {Object} - Input listener that speaks content on focus. This is the only input listener added
- // by Voicing, but it is the one that is consistent for all Voicing nodes. On focus, speak the name, object
- // response, and interaction hint.
- this.speakContentOnFocusListener = {
- focus: event => {
- this._voicingFocusListener( event );
- }
- };
- this.addInputListener( this.speakContentOnFocusListener );
- },
+ // @private {Object} - Input listener that speaks content on focus. This is the only input listener added
+ // by Voicing, but it is the one that is consistent for all Voicing nodes. On focus, speak the name, object
+ // response, and interaction hint.
+ this.speakContentOnFocusListener = {
+ focus: event => {
+ this._voicingFocusListener( event );
+ }
+ };
+ this.addInputListener( this.speakContentOnFocusListener );
+ }
- /**
- * Speak all responses assigned to this Node. Options allow you to override a responses for this particular
- * speech request. Each response is only spoken if the associated Property of responseCollector is true. If
- * all are Properties are false, nothing will be spoken.
- * @public
- *
- * @param {Object} [options]
- */
- voicingSpeakFullResponse( options ) {
- assert && assert( this.voicingInitialized, 'voicing must be initialized to speak' );
+ /**
+ * Speak all responses assigned to this Node. Options allow you to override a responses for this particular
+ * speech request. Each response is only spoken if the associated Property of responseCollector is true. If
+ * all are Properties are false, nothing will be spoken.
+ */
+ voicingSpeakFullResponse( providedOptions?: ResponseOptions ): void {
- // options are passed along to collectAndSpeakResponse, see that function for additional options
- options = merge( {
- nameResponse: this.voicingResponsePacket.nameResponse,
- objectResponse: this.voicingResponsePacket.objectResponse,
- contextResponse: this.voicingResponsePacket.contextResponse,
- hintResponse: this.voicingResponsePacket.hintResponse
- }, options );
+ // options are passed along to collectAndSpeakResponse, see that function for additional options
+ const options = optionize( {
+ nameResponse: this.voicingResponsePacket.nameResponse,
+ objectResponse: this.voicingResponsePacket.objectResponse,
+ contextResponse: this.voicingResponsePacket.contextResponse,
+ hintResponse: this.voicingResponsePacket.hintResponse
+ }, providedOptions );
- this.collectAndSpeakResponse( options );
- },
+ this.collectAndSpeakResponse( options );
+ }
- /**
- * Speak ONLY the provided responses that you pass in with options. This will NOT speak the name, object,
- * context, or hint responses assigned to this node by default. But it allows for clarity at usages so it is
- * clear that you are only requesting certain responses. If you want to speak all of the responses assigned
- * to this Node, use voicingSpeakFullResponse().
- *
- * Each response will only be spoken if the Properties of responseCollector are true. If all of those are false,
- * nothing will be spoken.
- * @public
- *
- * @param {Object} [options]
- */
- voicingSpeakResponse( options ) {
- assert && assert( this.voicingInitialized, 'voicing must be initialized to speak' );
+ /**
+ * Speak ONLY the provided responses that you pass in with options. This will NOT speak the name, object,
+ * context, or hint responses assigned to this node by default. But it allows for clarity at usages so it is
+ * clear that you are only requesting certain responses. If you want to speak all of the responses assigned
+ * to this Node, use voicingSpeakFullResponse().
+ *
+ * Each response will only be spoken if the Properties of responseCollector are true. If all of those are false,
+ * nothing will be spoken.
+ */
+ voicingSpeakResponse( providedOptions?: ResponseOptions ): void {
- // options are passed along to collectAndSpeakResponse, see that function for additional options
- options = merge( {
- nameResponse: null,
- objectResponse: null,
- contextResponse: null,
- hintResponse: null
- }, options );
+ // options are passed along to collectAndSpeakResponse, see that function for additional options
+ const options = optionize( {
+ nameResponse: null,
+ objectResponse: null,
+ contextResponse: null,
+ hintResponse: null
+ }, providedOptions );
- this.collectAndSpeakResponse( options );
- },
+ this.collectAndSpeakResponse( options );
+ }
- /**
- * By default, speak the name response. But accepts all other responses through options. Respects responseCollector
- * Properties, so the name response may not be spoken if responseCollector.nameResponseEnabledProperty is false.
- * @public
- *
- * @param {Object} [options]
- */
- voicingSpeakNameResponse( options ) {
- assert && assert( this.voicingInitialized, 'voicing must be initialized to speak' );
+ /**
+ * By default, speak the name response. But accepts all other responses through options. Respects responseCollector
+ * Properties, so the name response may not be spoken if responseCollector.nameResponseEnabledProperty is false.
+ */
+ voicingSpeakNameResponse( providedOptions?: ResponseOptions ): void {
- // options are passed along to collectAndSpeakResponse, see that function for additional options
- options = merge( {
- nameResponse: this.voicingResponsePacket.nameResponse
- }, options );
+ // options are passed along to collectAndSpeakResponse, see that function for additional options
+ const options = optionize( {
+ nameResponse: this.voicingResponsePacket.nameResponse
+ }, providedOptions );
- this.collectAndSpeakResponse( options );
- },
+ this.collectAndSpeakResponse( options );
+ }
- /**
- * By default, speak the object response. But accepts all other responses through options. Respects responseCollector
- * Properties, so the name response may not be spoken if responseCollector.objectResponseEnabledProperty is false.
- * @public
- *
- * @param {Object} [options]
- */
- voicingSpeakObjectResponse( options ) {
- assert && assert( this.voicingInitialized, 'voicing must be initialized to speak' );
+ /**
+ * By default, speak the object response. But accepts all other responses through options. Respects responseCollector
+ * Properties, so the name response may not be spoken if responseCollector.objectResponseEnabledProperty is false.
+ */
+ voicingSpeakObjectResponse( providedOptions?: ResponseOptions ): void {
- // options are passed along to collectAndSpeakResponse, see that function for additional options
- options = merge( {
- objectResponse: this.voicingResponsePacket.objectResponse
- }, options );
+ // options are passed along to collectAndSpeakResponse, see that function for additional options
+ const options = optionize( {
+ objectResponse: this.voicingResponsePacket.objectResponse
+ }, providedOptions );
- this.collectAndSpeakResponse( options );
- },
+ this.collectAndSpeakResponse( options );
+ }
- /**
- * By default, speak the context response. But accepts all other responses through options. Respects
- * responseCollector Properties, so the name response may not be spoken if
- * responseCollector.contextResponseEnabledProperty is false.
- * @public
- *
- * @param {Object} [options]
- */
- voicingSpeakContextResponse( options ) {
- assert && assert( this.voicingInitialized, 'voicing must be initialized to speak' );
+ /**
+ * By default, speak the context response. But accepts all other responses through options. Respects
+ * responseCollector Properties, so the name response may not be spoken if
+ * responseCollector.contextResponseEnabledProperty is false.
+ */
+ voicingSpeakContextResponse( providedOptions?: ResponseOptions ): void {
- // options are passed along to collectAndSpeakResponse, see that function for additional options
- options = merge( {
- contextResponse: this.voicingResponsePacket.contextResponse
- }, options );
+ // options are passed along to collectAndSpeakResponse, see that function for additional options
+ const options = optionize( {
+ contextResponse: this.voicingResponsePacket.contextResponse
+ }, providedOptions );
- this.collectAndSpeakResponse( options );
- },
+ this.collectAndSpeakResponse( options );
+ }
- /**
- * By default, speak the hint response. But accepts all other responses through options. Respects
- * responseCollector Properties, so the hint response may not be spoken if
- * responseCollector.hintResponseEnabledProperty is false.
- * @public
- *
- * @param {Object} [options]
- */
- voicingSpeakHintResponse( options ) {
- assert && assert( this.voicingInitialized, 'voicing must be initialized to speak' );
+ /**
+ * By default, speak the hint response. But accepts all other responses through options. Respects
+ * responseCollector Properties, so the hint response may not be spoken if
+ * responseCollector.hintResponseEnabledProperty is false.
+ */
+ voicingSpeakHintResponse( providedOptions?: ResponseOptions ): void {
- // options are passed along to collectAndSpeakResponse, see that function for additional options
- options = merge( {
- hintResponse: this.voicingResponsePacket.hintResponse
- }, options );
+ // options are passed along to collectAndSpeakResponse, see that function for additional options
+ const options = optionize( {
+ hintResponse: this.voicingResponsePacket.hintResponse
+ }, providedOptions );
- this.collectAndSpeakResponse( options );
- },
+ this.collectAndSpeakResponse( options );
+ }
- /**
- * Collect responses with the responseCollector and speak the output with an UtteranceQueue.
- * @protected
- *
- * @param {Object} [options]
- */
- collectAndSpeakResponse( options ) {
- options = merge( {
+ /**
+ * Collect responses with the responseCollector and speak the output with an UtteranceQueue.
+ *
+ * TODO: we want this to be @protected, https://github.com/phetsims/scenery/issues/1340
+ * @public
+ */
+ collectAndSpeakResponse( providedOptions?: ResponseOptions ): void {
+ const options = optionize( {
- // {boolean} - whether or not this response should ignore the Properties of responseCollector
- ignoreProperties: this.voicingResponsePacket.ignoreProperties,
+ // {boolean} - whether or not this response should ignore the Properties of responseCollector
+ ignoreProperties: this.voicingResponsePacket.ignoreProperties,
- // {Object} - collection of string patterns to use with responseCollector.collectResponses, see
- // ResponsePatternCollection for more information.
- responsePatternCollection: this.voicingResponsePacket.responsePatternCollection,
+ // {Object} - collection of string patterns to use with responseCollector.collectResponses, see
+ // ResponsePatternCollection for more information.
+ responsePatternCollection: this.voicingResponsePacket.responsePatternCollection,
- // {Utterance|null} - The utterance to use if you want this response to be more controlled in the
- // UtteranceQueue.
- utterance: null
- }, options );
+ // {Utterance|null} - The utterance to use if you want this response to be more controlled in the
+ // UtteranceQueue.
+ utterance: null
+ }, providedOptions );
- let response = responseCollector.collectResponses( options );
+ let response: AlertableDef = responseCollector.collectResponses( options );
- if ( options.utterance ) {
- options.utterance.alert = response;
- response = options.utterance;
- }
- this.speakContent( response );
- },
+ if ( options.utterance ) {
+ options.utterance.alert = response;
+ response = options.utterance;
+ }
+ this.speakContent( response );
+ }
- /**
- * Use the provided function to create content to speak in response to input. The content is then added to the
- * back of the voicing UtteranceQueue.
- * @protected
- *
- * @param {null|AlertableDef} content
- */
- speakContent( content ) {
+ /**
+ * Use the provided function to create content to speak in response to input. The content is then added to the
+ * back of the voicing UtteranceQueue.
+ *
+ * TODO: we want this to be @protected, https://github.com/phetsims/scenery/issues/1340
+ * @public
+ *
+ */
+ speakContent( content: AlertableDef | null ): void {
- // don't send to utteranceQueue if response is empty
- if ( content ) {
- const utteranceQueue = this.voicingUtteranceQueue || voicingUtteranceQueue;
- utteranceQueue.addToBack( content );
- }
- },
+ // don't send to utteranceQueue if response is empty
+ if ( content ) {
+ const utteranceQueue = this.voicingUtteranceQueue || voicingUtteranceQueue;
+ utteranceQueue.addToBack( content );
+ }
+ }
- /**
- * Sets the voicingNameResponse for this Node. This is usually the label of the element and is spoken
- * when the object receives input. When requesting speech, this will only be spoken if
- * responseCollector.nameResponsesEnabledProperty is set to true.
- *
- * @public
- *
- * @param {string|null} response
- */
- setVoicingNameResponse( response ) {
- this.voicingResponsePacket.nameResponse = response;
- },
- set voicingNameResponse( response ) { this.setVoicingNameResponse( response ); },
+ /**
+ * Sets the voicingNameResponse for this Node. This is usually the label of the element and is spoken
+ * when the object receives input. When requesting speech, this will only be spoken if
+ * responseCollector.nameResponsesEnabledProperty is set to true.
+ */
+ setVoicingNameResponse( response: string | null ): void {
+ this.voicingResponsePacket.nameResponse = response;
+ }
+
+ set voicingNameResponse( response ) { this.setVoicingNameResponse( response ); }
- /**
- * Get the voicingNameResponse for this Node.
- * @public
- *
- * @returns {string|null}
- */
- getVoicingNameResponse() {
- return this.voicingResponsePacket.nameResponse;
- },
- get voicingNameResponse() { return this.getVoicingNameResponse(); },
+ /**
+ * Get the voicingNameResponse for this Node.
+ */
+ getVoicingNameResponse() {
+ return this.voicingResponsePacket.nameResponse;
+ }
+
+ get voicingNameResponse() { return this.getVoicingNameResponse(); }
- /**
- * Set the object response for this Node. This is usually the state information associated with this Node, such
- * as its current input value. When requesting speech, this will only be heard when
- * responseCollector.objectResponsesEnabledProperty is set to true.
- * @public
- *
- * @param {string|null} response
- */
- setVoicingObjectResponse( response ) {
- this.voicingResponsePacket.objectResponse = response;
- },
- set voicingObjectResponse( response ) { this.setVoicingObjectResponse( response ); },
+ /**
+ * Set the object response for this Node. This is usually the state information associated with this Node, such
+ * as its current input value. When requesting speech, this will only be heard when
+ * responseCollector.objectResponsesEnabledProperty is set to true.
+ */
+ setVoicingObjectResponse( response: string | null ) {
+ this.voicingResponsePacket.objectResponse = response;
+ }
+
+ set voicingObjectResponse( response ) { this.setVoicingObjectResponse( response ); }
- /**
- * Gets the object response for this Node.
- * @public
- *
- * @returns {string|null}
- */
- getVoicingObjectResponse() {
- return this.voicingResponsePacket.objectResponse;
- },
- get voicingObjectResponse() { return this.getVoicingObjectResponse(); },
+ /**
+ * Gets the object response for this Node.
+ */
+ getVoicingObjectResponse() {
+ return this.voicingResponsePacket.objectResponse;
+ }
+
+ get voicingObjectResponse() { return this.getVoicingObjectResponse(); }
- /**
- * Set the context response for this Node. This is usually the content that describes what has happened in
- * the surrounding application in response to interaction with this Node. When requesting speech, this will
- * only be heard if responseCollector.contextResponsesEnabledProperty is set to true.
- * @public
- *
- * @param {string|null} response
- */
- setVoicingContextResponse( response ) {
- this.voicingResponsePacket.contextResponse = response;
- },
- set voicingContextResponse( response ) { this.setVoicingContextResponse( response ); },
+ /**
+ * Set the context response for this Node. This is usually the content that describes what has happened in
+ * the surrounding application in response to interaction with this Node. When requesting speech, this will
+ * only be heard if responseCollector.contextResponsesEnabledProperty is set to true.
+ */
+ setVoicingContextResponse( response: string | null ) {
+ this.voicingResponsePacket.contextResponse = response;
+ }
+
+ set voicingContextResponse( response ) { this.setVoicingContextResponse( response ); }
- /**
- * Gets the context response for this Node.
- * @public
- *
- * @returns {string|null}
- */
- getVoicingContextResponse() {
- return this.voicingResponsePacket.contextResponse;
- },
- get voicingContextResponse() { return this.getVoicingContextResponse(); },
+ /**
+ * Gets the context response for this Node.
+ */
+ getVoicingContextResponse() {
+ return this.voicingResponsePacket.contextResponse;
+ }
+
+ get voicingContextResponse() { return this.getVoicingContextResponse(); }
- /**
- * Sets the hint response for this Node. This is usually a response that describes how to interact with this Node.
- * When requesting speech, this will only be spoken when responseCollector.hintResponsesEnabledProperty is set to
- * true.
- * @public
- *
- * @param {string|null} response
- */
- setVoicingHintResponse( response ) {
- this.voicingResponsePacket.hintResponse = response;
- },
- set voicingHintResponse( response ) { this.setVoicingHintResponse( response ); },
+ /**
+ * Sets the hint response for this Node. This is usually a response that describes how to interact with this Node.
+ * When requesting speech, this will only be spoken when responseCollector.hintResponsesEnabledProperty is set to
+ * true.
+ */
+ setVoicingHintResponse( response: string | null ) {
+ this.voicingResponsePacket.hintResponse = response;
+ }
+
+ set voicingHintResponse( response ) { this.setVoicingHintResponse( response ); }
- /**
- * Gets the hint response for this Node.
- * @public
- *
- * @returns {string|null}
- */
- getVoicingHintResponse() {
- return this.voicingResponsePacket.hintResponse;
- },
- get voicingHintResponse() { return this.getVoicingHintResponse(); },
+ /**
+ * Gets the hint response for this Node.
+ */
+ getVoicingHintResponse() {
+ return this.voicingResponsePacket.hintResponse;
+ }
+
+ get voicingHintResponse() { return this.getVoicingHintResponse(); }
- /**
- * Set whether or not all responses for this Node will ignore the Properties of responseCollector. If false,
- * all responses will be spoken regardless of responseCollector Properties, which are generally set in user
- * preferences.
- * @public
- */
- setVoicingIgnoreVoicingManagerProperties( ignoreProperties ) {
- this.voicingResponsePacket.ignoreProperties = ignoreProperties;
- },
- set voicingIgnoreVoicingManagerProperties( ignoreProperties ) { this.setVoicingIgnoreVoicingManagerProperties( ignoreProperties ); },
+ /**
+ * Set whether or not all responses for this Node will ignore the Properties of responseCollector. If false,
+ * all responses will be spoken regardless of responseCollector Properties, which are generally set in user
+ * preferences.
+ */
+ setVoicingIgnoreVoicingManagerProperties( ignoreProperties: boolean ) {
+ this.voicingResponsePacket.ignoreProperties = ignoreProperties;
+ }
+
+ set voicingIgnoreVoicingManagerProperties( ignoreProperties ) { this.setVoicingIgnoreVoicingManagerProperties( ignoreProperties ); }
- /**
- * Get whether or not responses are ignoring responseCollector Properties.
- */
- getVoicingIgnoreVoicingManagerProperties() {
- return this.voicingResponsePacket.ignoreProperties;
- },
- get voicingIgnoreVoicingManagerProperties() { return this.getVoicingIgnoreVoicingManagerProperties(); },
+ /**
+ * Get whether or not responses are ignoring responseCollector Properties.
+ */
+ getVoicingIgnoreVoicingManagerProperties() {
+ return this.voicingResponsePacket.ignoreProperties;
+ }
+
+ get voicingIgnoreVoicingManagerProperties() { return this.getVoicingIgnoreVoicingManagerProperties(); }
- /**
- * Sets the collection of patterns to use for voicing responses, controlling the order, punctuation, and
- * additional content for each combination of response. See ResponsePatternCollection.js if you wish to use
- * a collection of string patterns that are not the default.
- * @public
- *
- * @param {ResponsePatternCollection} patterns - see ResponsePatternCollection
- */
- setVoicingResponsePatternCollection( patterns ) {
- assert && assert( patterns instanceof ResponsePatternCollection );
- this.voicingResponsePacket.responsePatternCollection = patterns;
- },
- set voicingResponsePatternCollection( patterns ) { this.setVoicingResponsePatternCollection( patterns ); },
+ /**
+ * Sets the collection of patterns to use for voicing responses, controlling the order, punctuation, and
+ * additional content for each combination of response. See ResponsePatternCollection.js if you wish to use
+ * a collection of string patterns that are not the default.
+ */
+ setVoicingResponsePatternCollection( patterns: ResponsePatternCollection ) {
+ assert && assert( patterns instanceof ResponsePatternCollection );
+ this.voicingResponsePacket.responsePatternCollection = patterns;
+ }
+
+ set voicingResponsePatternCollection( patterns ) { this.setVoicingResponsePatternCollection( patterns ); }
- /**
- * Get the ResponsePatternCollection object that this Voicing Node is using to collect responses.
- * @public
- *
- * @returns {ResponsePatternCollection}
- */
- getVoicingResponsePatternCollection() {
- return this.voicingResponsePacket.responsePatternCollection;
- },
- get voicingResponsePatternCollection() { return this.getVoicingResponsePatternCollection(); },
+ /**
+ * Get the ResponsePatternCollection object that this Voicing Node is using to collect responses.
+ */
+ getVoicingResponsePatternCollection() {
+ return this.voicingResponsePacket.responsePatternCollection;
+ }
+
+ get voicingResponsePatternCollection() { return this.getVoicingResponsePatternCollection(); }
- /**
- * Sets the utteranceQueue through which voicing associated with this Node will be spoken. By default,
- * the Display's voicingUtteranceQueue is used. But you can specify a different one if more complicated
- * management of voicing is necessary.
- * @public
- *
- * @param {UtteranceQueue} utteranceQueue
- */
- setVoicingUtteranceQueue( utteranceQueue ) {
- this._voicingUtteranceQueue = utteranceQueue;
- },
+ /**
+ * Sets the utteranceQueue through which voicing associated with this Node will be spoken. By default,
+ * the Display's voicingUtteranceQueue is used. But you can specify a different one if more complicated
+ * management of voicing is necessary.
+ */
+ setVoicingUtteranceQueue( utteranceQueue: UtteranceQueue | null ) {
+ this._voicingUtteranceQueue = utteranceQueue;
+ }
- set voicingUtteranceQueue( utteranceQueue ) { this.setVoicingUtteranceQueue( utteranceQueue ); },
+ set voicingUtteranceQueue( utteranceQueue: UtteranceQueue | null ) { this.setVoicingUtteranceQueue( utteranceQueue ); }
- /**
- * Gets the utteranceQueue through which voicing associated with this Node will be spoken.
- * @public
- *
- * @returns {UtteranceQueue}
- */
- getVoicingUtteranceQueue() {
- return this._voicingUtteranceQueue;
- },
- get voicingUtteranceQueue() { return this.getVoicingUtteranceQueue(); },
+ /**
+ * Gets the utteranceQueue through which voicing associated with this Node will be spoken.
+ */
+ getVoicingUtteranceQueue() {
+ return this._voicingUtteranceQueue;
+ }
+
+ get voicingUtteranceQueue() { return this.getVoicingUtteranceQueue(); }
- /**
- * Called whenever this Node is focused.
- * @public
- *
- * @param {function(SceneryEvent):} focusListener
- */
- setVoicingFocusListener( focusListener ) {
- this._voicingFocusListener = focusListener;
- },
+ /**
+ * Called whenever this Node is focused.
+ */
+ setVoicingFocusListener( focusListener: SceneryListener ) {
+ this._voicingFocusListener = focusListener;
+ }
- set voicingFocusListener( utteranceQueue ) { this.setVoicingFocusListener( utteranceQueue ); },
+ set voicingFocusListener( focusListener: SceneryListener ) { this.setVoicingFocusListener( focusListener ); }
- /**
- * Gets the utteranceQueue through which voicing associated with this Node will be spoken.
- * @public
- *
- * @returns {UtteranceQueue}
- */
- getVoicingFocusListener() {
- return this._voicingFocusListener;
- },
- get voicingFocusListener() { return this.getVoicingFocusListener(); },
+ /**
+ * Gets the utteranceQueue through which voicing associated with this Node will be spoken.
+ */
+ getVoicingFocusListener(): SceneryListener {
+ return this._voicingFocusListener;
+ }
+
+ get voicingFocusListener() { return this.getVoicingFocusListener(); }
- /**
- * The default focus listener attached to this Node during initialization.
- * @public
- */
- defaultFocusListener() {
- this.voicingSpeakFullResponse( {
- contextResponse: null
- } );
- },
+ /**
+ * The default focus listener attached to this Node during initialization.
+ */
+ defaultFocusListener(): void {
+ this.voicingSpeakFullResponse( {
+ contextResponse: null
+ } );
+ }
- /**
- * Whether or not a Node composes Voicing.
- * @public
- * @returns {boolean}
- */
- get isVoicing() {
- return true;
- },
+ /**
+ * Whether or not a Node composes Voicing.
+ */
+ get isVoicing() {
+ return true;
+ }
- /**
- * Detaches references that ensure this components of this Trait are eligible for garbage collection.
- * @public
- */
- disposeVoicing() {
- this.voicingInitialized = false;
- this.removeInputListener( this.speakContentOnFocusListener );
- this.disposeInteractiveHighlighting();
- }
- } );
- }
+ /**
+ * Detaches references that ensure this components of this Trait are eligible for garbage collection.
+ * @public
+ */
+ disposeVoicing() {
+ this.removeInputListener( this.speakContentOnFocusListener );
+
+ // @ts-ignore
+ this.disposeInteractiveHighlighting();
+ }
+ };
+
+ // compose with Interactive Highlights, all Nodes with Voicing features highlight as they are interactive
+ InteractiveHighlighting.compose( X );
+
+ /**
+ * {Array.} - String keys for all of the allowed options that will be set by node.mutate( options ), in
+ * the order they will be evaluated.
+ *
+ * TODO: we want this to be @protected, https://github.com/phetsims/scenery/issues/1340
+ * @public
+ *
+ * NOTE: See Node's _mutatorKeys documentation for more information on how this operates, and potential special
+ * cases that may apply.
+ */
+ X.prototype._mutatorKeys = _.uniq( ( X.prototype._mutatorKeys ? X.prototype._mutatorKeys : [] ).concat( VOICING_OPTION_KEYS ) );
+ return X;
};
// @pulic
Index: scenery/js/accessibility/voicing/ReadingBlock.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/voicing/ReadingBlock.js b/scenery/js/accessibility/voicing/ReadingBlock.js
--- a/scenery/js/accessibility/voicing/ReadingBlock.js (revision faa4e9d6dbd874a6d3bd9a0b6dd4acabb54651b9)
+++ b/scenery/js/accessibility/voicing/ReadingBlock.js (date 1643066948389)
@@ -19,7 +19,6 @@
import TinyEmitter from '../../../../axon/js/TinyEmitter.js';
import Shape from '../../../../kite/js/Shape.js';
-import extend from '../../../../phet-core/js/extend.js';
import inheritance from '../../../../phet-core/js/inheritance.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import responseCollector from '../../../../utterance-queue/js/responseCollector.js';
@@ -34,350 +33,344 @@
const CONTENT_HINT_PATTERN = '{{readingBlockContent}}. {{hintResponse}}';
-const ReadingBlock = {
-
- /**
- * @public
- * @trait {Node}
- * @mixes {Voicing}
- * @param {function(new:Node)} type - The constructor for Node
- */
- compose( type ) {
- assert && assert( _.includes( inheritance( type ), Node ) );
+const ReadingBlock = Type => {
- const proto = type.prototype;
+ assert && assert( _.includes( inheritance( Type ), Node ), 'Only Node subtypes should compose Voicing' );
- // compose with Voicing
- Voicing.compose( type );
+ const X = class extends Voicing( Type ) {
- extend( proto, {
-
- /**
- * {Array.} - String keys for all of the allowed options that will be set by node.mutate( options ), in
- * the order they will be evaluated.
- * @protected
- *
- * NOTE: See Node's _mutatorKeys documentation for more information on how this operates, and potential special
- * cases that may apply.
- */
- _mutatorKeys: READING_BLOCK_OPTION_KEYS.concat( proto._mutatorKeys ),
- /**
- * This should be called in the constructor to initialize ReadingBlock. Note, this must be called before
- * options are mutated, so most often you must call options via `mutate()` instead of passing directly to
- * `super()`.
- */
- initializeReadingBlock() {
+ /**
+ * This should be called in the constructor to initialize ReadingBlock. Note, this must be called before
+ * options are mutated, so most often you must call options via `mutate()` instead of passing directly to
+ * `super()`.
+ */
+ constructor( ...args ) {
- // initialize the parent trait
- this.initializeVoicing();
+ super( ...args );
- // @private {boolean} - to make sure that initializeReadingBlock is called before trying to use trait features
- this.readingBlockInitialized = true;
+ // TODO: delete, https://github.com/phetsims/scenery/issues/1340
+ // @private {boolean} - to make sure that initializeReadingBlock is called before trying to use trait features
+ this.readingBlockInitialized = true;
- // @private {string|null} - The tagName used for the ReadingBlock when "Voicing" is enabled, default
- // of button so that it is added to the focus order and can receive 'click' events. You may wish to set this
- // to some other tagName or set to null to remove the ReadingBlock from the focus order. If this is changed,
- // be be sure that the ReadingBlock will still respond to `click` events when enabled.
- this._readingBlockTagName = 'button';
+ // @private {string|null} - The tagName used for the ReadingBlock when "Voicing" is enabled, default
+ // of button so that it is added to the focus order and can receive 'click' events. You may wish to set this
+ // to some other tagName or set to null to remove the ReadingBlock from the focus order. If this is changed,
+ // be be sure that the ReadingBlock will still respond to `click` events when enabled.
+ this._readingBlockTagName = 'button';
- // @private {string|null} - The content for this ReadingBlock that will be spoken by SpeechSynthesis when
- // the ReadingBlock receives input. ReadingBlocks don't use the categories of Voicing content provided by
- // Voicing.js because ReadingBlocks are always spoken regardless of the Properties of responseCollector.
- this._readingBlockContent = null;
+ // @private {string|null} - The content for this ReadingBlock that will be spoken by SpeechSynthesis when
+ // the ReadingBlock receives input. ReadingBlocks don't use the categories of Voicing content provided by
+ // Voicing.ts because ReadingBlocks are always spoken regardless of the Properties of responseCollector.
+ this._readingBlockContent = null;
- // @private {string|null} - The help content that is read when this ReadingBlock is activated by input,
- // but only when "Helpful Hints" is enabled by the user.
- this._readingBlockHintResponse = null;
+ // @private {string|null} - The help content that is read when this ReadingBlock is activated by input,
+ // but only when "Helpful Hints" is enabled by the user.
+ this._readingBlockHintResponse = null;
- // @private {string} - The tagName to apply to the Node when voicing is disabled.
- this._readingBlockDisabledTagName = 'p';
+ // @private {string} - The tagName to apply to the Node when voicing is disabled.
+ this._readingBlockDisabledTagName = 'p';
- // @private {null|Shape|Node} - The highlight that surrounds this ReadingBlock when it is "active" and
- // the Voicing framework is speaking the content associated with this Node. By default, a semi-transparent
- // yellow highlight surrounds this Node's bounds.
- this._readingBlockActiveHighlight = null;
+ // @private {null|Shape|Node} - The highlight that surrounds this ReadingBlock when it is "active" and
+ // the Voicing framework is speaking the content associated with this Node. By default, a semi-transparent
+ // yellow highlight surrounds this Node's bounds.
+ this._readingBlockActiveHighlight = null;
- // @public (scenery-internal) {TinyEmitter} - Sends a message when the highlight for the ReadingBlock changes. Used
- // by the HighlightOverlay to redraw it if it changes while the highlight is active.
- this.readingBlockActiveHighlightChangedEmitter = new TinyEmitter();
+ // @public (scenery-internal) {TinyEmitter} - Sends a message when the highlight for the ReadingBlock changes. Used
+ // by the HighlightOverlay to redraw it if it changes while the highlight is active.
+ this.readingBlockActiveHighlightChangedEmitter = new TinyEmitter();
- // @private {function} - Updates the hit bounds of this Node when the local bounds change.
- this.localBoundsChangedListener = this.onLocalBoundsChanged.bind( this );
- this.localBoundsProperty.link( this.localBoundsChangedListener );
+ // @private {function} - Updates the hit bounds of this Node when the local bounds change.
+ this.localBoundsChangedListener = this.onLocalBoundsChanged.bind( this );
+ this.localBoundsProperty.link( this.localBoundsChangedListener );
- // @private {Object} - Triggers activation of the ReadingBlock, requesting speech of its content.
- this.readingBlockInputListener = {
- focus: event => this.speakReadingBlockContent( event ),
- up: event => this.speakReadingBlockContent( event ),
- click: event => this.speakReadingBlockContent( event )
- };
+ // @private {Object} - Triggers activation of the ReadingBlock, requesting speech of its content.
+ this.readingBlockInputListener = {
+ focus: event => this.speakReadingBlockContent( event ),
+ up: event => this.speakReadingBlockContent( event ),
+ click: event => this.speakReadingBlockContent( event )
+ };
- // @private - Controls whether or not the ReadingBlock should be interactiveand focusable.
- // At the time of this writing, that is true for all ReadingBlocks when the voicingManager is
- // fully enabled and can speak.
- this.readingBlockFocusableChangeListener = this.onReadingBlockFocusableChanged.bind( this );
- voicingManager.speechAllowedAndFullyEnabledProperty.link( this.readingBlockFocusableChangeListener );
+ // @private - Controls whether or not the ReadingBlock should be interactiveand focusable.
+ // At the time of this writing, that is true for all ReadingBlocks when the voicingManager is
+ // fully enabled and can speak.
+ this.readingBlockFocusableChangeListener = this.onReadingBlockFocusableChanged.bind( this );
+ voicingManager.speechAllowedAndFullyEnabledProperty.link( this.readingBlockFocusableChangeListener );
- // All ReadingBlocks have a ReadingBlockHighlight, a focus highlight that is black to indicate it has
- // a different behavior.
- this.focusHighlight = new ReadingBlockHighlight( this );
- },
+ // All ReadingBlocks have a ReadingBlockHighlight, a focus highlight that is black to indicate it has
+ // a different behavior.
+ this.focusHighlight = new ReadingBlockHighlight( this );
+ }
- /**
- * Whether or not a Node composes ReadingBlock.
- * @returns {boolean}
- */
- get isReadingBlock() {
- return true;
- },
+ /**
+ * Whether or not a Node composes ReadingBlock.
+ * @returns {boolean}
+ */
+ get isReadingBlock() {
+ return true;
+ }
- /**
- * Set the tagName for the ReadingBlockNode. This is the tagName (of ParallelDOM) that will be applied
- * to this Node when Reading Blocks are enabled.
- * @public
- *
- * @param {string|null} tagName
- */
- setReadingBlockTagName( tagName ) {
- this._readingBlockTagName = tagName;
- this.onReadingBlockFocusableChanged( voicingManager.speechAllowedAndFullyEnabledProperty.value );
- },
- set readingBlockTagName( tagName ) { this.setReadingBlockTagName( tagName ); },
+ /**
+ * Set the tagName for the ReadingBlockNode. This is the tagName (of ParallelDOM) that will be applied
+ * to this Node when Reading Blocks are enabled.
+ * @public
+ *
+ * @param {string|null} tagName
+ */
+ setReadingBlockTagName( tagName ) {
+ this._readingBlockTagName = tagName;
+ this.onReadingBlockFocusableChanged( voicingManager.speechAllowedAndFullyEnabledProperty.value );
+ }
+
+ set readingBlockTagName( tagName ) { this.setReadingBlockTagName( tagName ); }
- /**
- * Get the tagName for this Node (of ParallelDOM) when Reading Blocks are enabled.
- * @public
- *
- * @returns {string|null}
- */
- getReadingBlockTagName() {
- return this._readingBlockTagName;
- },
- get readingBlockTagName() { return this.getReadingBlockTagName(); },
+ /**
+ * Get the tagName for this Node (of ParallelDOM) when Reading Blocks are enabled.
+ * @public
+ *
+ * @returns {string|null}
+ */
+ getReadingBlockTagName() {
+ return this._readingBlockTagName;
+ }
+
+ get readingBlockTagName() { return this.getReadingBlockTagName(); }
- /**
- * Sets the content that should be read whenever the ReadingBlock receives input that initiates speech.
- * @public
- *
- * @param {string|null} content
- */
- setReadingBlockContent( content ) {
- this._readingBlockContent = content;
- },
- set readingBlockContent( content ) { this.setReadingBlockContent( content ); },
+ /**
+ * Sets the content that should be read whenever the ReadingBlock receives input that initiates speech.
+ * @public
+ *
+ * @param {string|null} content
+ */
+ setReadingBlockContent( content ) {
+ this._readingBlockContent = content;
+ }
+
+ set readingBlockContent( content ) { this.setReadingBlockContent( content ); }
- /**
- * Gets the content that is spoken whenever the ReadingBLock receives input that would initiate speech.
- * @public
- *
- * @returns {string|null}
- */
- getReadingBlockContent() {
- return this._readingBlockContent;
- },
- get readingBlockContent() { return this.getReadingBlockContent(); },
+ /**
+ * Gets the content that is spoken whenever the ReadingBLock receives input that would initiate speech.
+ * @public
+ *
+ * @returns {string|null}
+ */
+ getReadingBlockContent() {
+ return this._readingBlockContent;
+ }
+
+ get readingBlockContent() { return this.getReadingBlockContent(); }
- /**
- * Sets the hint response for this ReadingBlock. This is only spoken if "Helpful Hints" are enabled by the user.
- * @public
- *
- * @param {string|null} content
- */
- setReadingBlockHintResponse( content ) {
- this._readingBlockHintResponse = content;
- },
- set readingBlockHintResponse( content ) { this.setReadingBlockHintResponse( content ); },
+ /**
+ * Sets the hint response for this ReadingBlock. This is only spoken if "Helpful Hints" are enabled by the user.
+ * @public
+ *
+ * @param {string|null} content
+ */
+ setReadingBlockHintResponse( content ) {
+ this._readingBlockHintResponse = content;
+ }
+
+ set readingBlockHintResponse( content ) { this.setReadingBlockHintResponse( content ); }
- /**
- * Get the hint response for this ReadingBlock. This is additional content that is only read if "Helpful Hints"
- * are enabled.
- * @public
- *
- * @returns {string|null}
- */
- getReadingBlockHintResponse() {
- return this._readingBlockHintResponse;
- },
- get readingBlockHintResponse() { return this.getReadingBlockHintResponse(); },
+ /**
+ * Get the hint response for this ReadingBlock. This is additional content that is only read if "Helpful Hints"
+ * are enabled.
+ * @public
+ *
+ * @returns {string|null}
+ */
+ getReadingBlockHintResponse() {
+ return this._readingBlockHintResponse;
+ }
+
+ get readingBlockHintResponse() { return this.getReadingBlockHintResponse(); }
- /**
- * Sets the highlight used to surround this Node while the Voicing framework is speaking this content.
- * Do not add this Node to the scene graph, it is added and made visible by the HighlightOverlay.
- * @public
- *
- * @param readingBlockActiveHighlight
- */
- setReadingBlockActiveHighlight( readingBlockActiveHighlight ) {
- assert && assert( readingBlockActiveHighlight === null ||
- readingBlockActiveHighlight instanceof Node ||
- readingBlockActiveHighlight instanceof Shape );
+ /**
+ * Sets the highlight used to surround this Node while the Voicing framework is speaking this content.
+ * Do not add this Node to the scene graph, it is added and made visible by the HighlightOverlay.
+ * @public
+ *
+ * @param readingBlockActiveHighlight
+ */
+ setReadingBlockActiveHighlight( readingBlockActiveHighlight ) {
+ assert && assert( readingBlockActiveHighlight === null ||
+ readingBlockActiveHighlight instanceof Node ||
+ readingBlockActiveHighlight instanceof Shape );
- if ( this._readingBlockActiveHighlight !== readingBlockActiveHighlight ) {
- this._readingBlockActiveHighlight = readingBlockActiveHighlight;
+ if ( this._readingBlockActiveHighlight !== readingBlockActiveHighlight ) {
+ this._readingBlockActiveHighlight = readingBlockActiveHighlight;
- if ( this.readingBlockInitialized ) {
- this.readingBlockActiveHighlightChangedEmitter.emit();
- }
- }
- },
- set readingBlockActiveHighlight( readingBlockActiveHighlight ) { this.setReadingBlockActiveHighlight( readingBlockActiveHighlight ); },
+ if ( this.readingBlockInitialized ) {
+ this.readingBlockActiveHighlightChangedEmitter.emit();
+ }
+ }
+ }
+
+ set readingBlockActiveHighlight( readingBlockActiveHighlight ) { this.setReadingBlockActiveHighlight( readingBlockActiveHighlight ); }
- /**
- * Returns the highlight used to surround this Node when the Voicing framework is reading its
- * content.
- * @returns {null|Shape|Node}
- */
- getReadingBlockActiveHighlight() {
- return this._readingBlockActiveHighlight;
- },
- get readingBlockActiveHighlight() { return this._readingBlockActiveHighlight; },
+ /**
+ * Returns the highlight used to surround this Node when the Voicing framework is reading its
+ * content.
+ * @returns {null|Shape|Node}
+ * @public
+ */
+ getReadingBlockActiveHighlight() {
+ return this._readingBlockActiveHighlight;
+ }
+
+ get readingBlockActiveHighlight() { return this._readingBlockActiveHighlight; }
- /**
- * Returns true if this ReadingBlock is "activated", indicating that it has received interaction
- * and the Voicing framework is speaking its content.
- * @public
- *
- * @returns {boolean}
- */
- isReadingBlockActivated() {
- let activated = false;
+ /**
+ * Returns true if this ReadingBlock is "activated", indicating that it has received interaction
+ * and the Voicing framework is speaking its content.
+ * @public
+ *
+ * @returns {boolean}
+ */
+ isReadingBlockActivated() {
+ let activated = false;
- const trailIds = Object.keys( this._displays );
- for ( let i = 0; i < trailIds.length; i++ ) {
- const pointerFocus = this._displays[ trailIds[ i ] ].focusManager.readingBlockFocusProperty.value;
- if ( pointerFocus && pointerFocus.trail.lastNode() === this ) {
- activated = true;
- break;
- }
- }
- return activated;
- },
- get readingBlockActivated() { return this.isReadingBlockActivated(); },
+ const trailIds = Object.keys( this._displays );
+ for ( let i = 0; i < trailIds.length; i++ ) {
+ const pointerFocus = this._displays[ trailIds[ i ] ].focusManager.readingBlockFocusProperty.value;
+ if ( pointerFocus && pointerFocus.trail.lastNode() === this ) {
+ activated = true;
+ break;
+ }
+ }
+ return activated;
+ }
+
+ get readingBlockActivated() { return this.isReadingBlockActivated(); }
- /**
- * When this Node becomes focusable (because Reading Blocks have just been enabled or disabled), either
- * apply or remove the readingBlockTagName.
- * @private
- *
- * @param {boolean} focusable - whether or not ReadingBlocks should be focusable
- */
- onReadingBlockFocusableChanged( focusable ) {
+ /**
+ * When this Node becomes focusable (because Reading Blocks have just been enabled or disabled), either
+ * apply or remove the readingBlockTagName.
+ * @private
+ *
+ * @param {boolean} focusable - whether or not ReadingBlocks should be focusable
+ */
+ onReadingBlockFocusableChanged( focusable ) {
- // wait until we have been initialized, it is possible to call setters from mutate before properties of
- // ReadingBlock are defined
- if ( !this.readingBlockInitialized ) {
- return;
- }
+ // wait until we have been initialized, it is possible to call setters from mutate before properties of
+ // ReadingBlock are defined
+ if ( !this.readingBlockInitialized ) {
+ return;
+ }
- this.focusable = focusable;
+ this.focusable = focusable;
- if ( focusable ) {
- this.tagName = this._readingBlockTagName;
+ if ( focusable ) {
+ this.tagName = this._readingBlockTagName;
- // don't add the input listener if we are already active, we may just be updating the tagName in this case
- if ( !this.hasInputListener( this.readingBlockInputListener ) ) {
- this.addInputListener( this.readingBlockInputListener );
- }
- }
- else {
- this.tagName = this._readingBlockDisabledTagName;
- if ( this.hasInputListener( this.readingBlockInputListener ) ) {
- this.removeInputListener( this.readingBlockInputListener );
- }
- }
- },
+ // don't add the input listener if we are already active, we may just be updating the tagName in this case
+ if ( !this.hasInputListener( this.readingBlockInputListener ) ) {
+ this.addInputListener( this.readingBlockInputListener );
+ }
+ }
+ else {
+ this.tagName = this._readingBlockDisabledTagName;
+ if ( this.hasInputListener( this.readingBlockInputListener ) ) {
+ this.removeInputListener( this.readingBlockInputListener );
+ }
+ }
+ }
- /**
- * Update the hit areas for this Node whenever the bounds change.
- * @private
- *
- * @param localBounds
- */
- onLocalBoundsChanged( localBounds ) {
- this.mouseArea = localBounds;
- this.touchArea = localBounds;
- },
+ /**
+ * Update the hit areas for this Node whenever the bounds change.
+ * @private
+ *
+ * @param localBounds
+ */
+ onLocalBoundsChanged( localBounds ) {
+ this.mouseArea = localBounds;
+ this.touchArea = localBounds;
+ }
- /**
- * Speak the content associated with the ReadingBlock. Sets the readingBlockFocusProperties on
- * the displays so that HighlightOverlays know to activate a highlight while the voicingManager
- * is reading about this Node.
- * @private
- *
- * @param {SceneryEvent} event
- */
- speakReadingBlockContent( event ) {
- assert && assert( this.readingBlockInitialized, 'ReadingBlock must be initialized before speaking' );
+ /**
+ * Speak the content associated with the ReadingBlock. Sets the readingBlockFocusProperties on
+ * the displays so that HighlightOverlays know to activate a highlight while the voicingManager
+ * is reading about this Node.
+ * @private
+ *
+ * @param {SceneryEvent} event
+ */
+ speakReadingBlockContent( event ) {
+ assert && assert( this.readingBlockInitialized, 'ReadingBlock must be initialized before speaking' );
- const displays = this.getConnectedDisplays();
+ const displays = this.getConnectedDisplays();
- const content = this.collectReadingBlockResponses();
- if ( content ) {
- for ( let i = 0; i < displays.length; i++ ) {
- if ( !this.getDescendantsUseHighlighting( event.trail ) ) {
+ const content = this.collectReadingBlockResponses();
+ if ( content ) {
+ for ( let i = 0; i < displays.length; i++ ) {
+ if ( !this.getDescendantsUseHighlighting( event.trail ) ) {
- // the SceneryEvent might have gone through a descendant of this Node
- const rootToSelf = event.trail.subtrailTo( this );
+ // the SceneryEvent might have gone through a descendant of this Node
+ const rootToSelf = event.trail.subtrailTo( this );
- // the trail to a Node may be discontinuous for PDOM events due to pdomOrder,
- // this finds the actual visual trail to use
- const visualTrail = scenery.PDOMInstance.guessVisualTrail( rootToSelf, displays[ i ].rootNode );
+ // the trail to a Node may be discontinuous for PDOM events due to pdomOrder,
+ // this finds the actual visual trail to use
+ const visualTrail = scenery.PDOMInstance.guessVisualTrail( rootToSelf, displays[ i ].rootNode );
- const focus = new Focus( displays[ i ], visualTrail );
- const readingBlockUtterance = new ReadingBlockUtterance( focus, {
- alert: content
- } );
- this.speakContent( readingBlockUtterance );
- }
- }
- }
- },
+ const focus = new Focus( displays[ i ], visualTrail );
+ const readingBlockUtterance = new ReadingBlockUtterance( focus, {
+ alert: content
+ } );
+ this.speakContent( readingBlockUtterance );
+ }
+ }
+ }
+ }
- /**
- * Collect responses for the ReadingBlock, putting together the content and the hint response. The hint response
- * is only read if it exists and hints are enabled by the user. Otherwise, only the readingBlock content will
- * be spoken.
- * @returns {string}
- */
- collectReadingBlockResponses() {
- assert && assert( this.readingBlockInitialized, 'ReadingBlock must be initialized before collecting responses' );
+ /**
+ * Collect responses for the ReadingBlock, putting together the content and the hint response. The hint response
+ * is only read if it exists and hints are enabled by the user. Otherwise, only the readingBlock content will
+ * be spoken.
+ * @returns {string}
+ * @public
+ */
+ collectReadingBlockResponses() {
+ assert && assert( this.readingBlockInitialized, 'ReadingBlock must be initialized before collecting responses' );
- const usesHelpContent = this._readingBlockHintResponse && responseCollector.hintResponsesEnabledProperty.value;
+ const usesHelpContent = this._readingBlockHintResponse && responseCollector.hintResponsesEnabledProperty.value;
- let response = null;
- if ( usesHelpContent ) {
- response = StringUtils.fillIn( CONTENT_HINT_PATTERN, {
- readingBlockContent: this._readingBlockContent,
- hintResponse: this._readingBlockHintResponse
- } );
- }
- else {
- response = this._readingBlockContent;
- }
+ let response = null;
+ if ( usesHelpContent ) {
+ response = StringUtils.fillIn( CONTENT_HINT_PATTERN, {
+ readingBlockContent: this._readingBlockContent,
+ hintResponse: this._readingBlockHintResponse
+ } );
+ }
+ else {
+ response = this._readingBlockContent;
+ }
- return response;
- },
+ return response;
+ }
- /**
- * @public
- */
- disposeReadingBlock() {
- this.readingBlockInitialized = false;
- voicingManager.speechAllowedAndFullyEnabledProperty.unlink( this.readingBlockFocusableChangeListener );
- this.localBoundsProperty.unlink( this.localBoundsChangedListener );
+ /**
+ * @public
+ */
+ disposeReadingBlock() {
+ this.readingBlockInitialized = false;
+ voicingManager.speechAllowedAndFullyEnabledProperty.unlink( this.readingBlockFocusableChangeListener );
+ this.localBoundsProperty.unlink( this.localBoundsChangedListener );
- // remove the input listener that activates the ReadingBlock, only do this if the listener is attached while
- // the ReadingBlock is enabled
- if ( this.hasInputListener( this.readingBlockInputListener ) ) {
- this.removeInputListener( this.readingBlockInputListener );
- }
+ // remove the input listener that activates the ReadingBlock, only do this if the listener is attached while
+ // the ReadingBlock is enabled
+ if ( this.hasInputListener( this.readingBlockInputListener ) ) {
+ this.removeInputListener( this.readingBlockInputListener );
+ }
- this.disposeVoicing();
- }
- } );
- }
+ this.disposeVoicing();
+ }
+ };
+
+
+ X.prototype._mutatorKeys = _.uniq( ( X.prototype._mutatorKeys ? X.prototype._mutatorKeys : [] ).concat( READING_BLOCK_OPTION_KEYS ) );
+ return X;
};
+
scenery.register( 'ReadingBlock', ReadingBlock );
export default ReadingBlock;
Index: scenery/js/accessibility/voicing/ReadingBlockNode.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/voicing/ReadingBlockNode.js b/scenery/js/accessibility/voicing/ReadingBlockNode.js
--- a/scenery/js/accessibility/voicing/ReadingBlockNode.js (revision faa4e9d6dbd874a6d3bd9a0b6dd4acabb54651b9)
+++ b/scenery/js/accessibility/voicing/ReadingBlockNode.js (date 1643062484395)
@@ -17,7 +17,7 @@
import merge from '../../../../phet-core/js/merge.js';
import { scenery, Node, ReadingBlock, ReadingBlockHighlight } from '../../imports.js';
-class ReadingBlockNode extends Node {
+class ReadingBlockNode extends ReadingBlock( Node ) {
/**
* @param {Object} [options]
@@ -31,7 +31,6 @@
}, options );
super();
- this.initializeReadingBlock();
// default highlight for a ReadingBlock is styled to indicate that the Node is different
// from other interactive things, but is still clickable
@@ -42,7 +41,5 @@
}
}
-ReadingBlock.compose( ReadingBlockNode );
-
scenery.register( 'ReadingBlockNode', ReadingBlockNode );
export default ReadingBlockNode;
\ No newline at end of file
Index: scenery/js/accessibility/voicing/nodes/VoicingRichText.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/voicing/nodes/VoicingRichText.js b/scenery/js/accessibility/voicing/nodes/VoicingRichText.js
--- a/scenery/js/accessibility/voicing/nodes/VoicingRichText.js (revision faa4e9d6dbd874a6d3bd9a0b6dd4acabb54651b9)
+++ b/scenery/js/accessibility/voicing/nodes/VoicingRichText.js (date 1643062484389)
@@ -10,7 +10,7 @@
import merge from '../../../../../phet-core/js/merge.js';
import { ReadingBlock, ReadingBlockHighlight, RichText, scenery } from '../../../imports.js';
-class VoicingRichText extends RichText {
+class VoicingRichText extends ReadingBlock( RichText ) {
/**
* @param {string} text
@@ -41,8 +41,6 @@
this.focusHighlight = new ReadingBlockHighlight( this );
- this.initializeReadingBlock();
-
this.mutate( options );
}
@@ -55,7 +53,5 @@
}
}
-ReadingBlock.compose( VoicingRichText );
-
scenery.register( 'VoicingRichText', VoicingRichText );
export default VoicingRichText;
Index: scenery/js/accessibility/voicing/nodes/VoicingText.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/js/accessibility/voicing/nodes/VoicingText.js b/scenery/js/accessibility/voicing/nodes/VoicingText.js
--- a/scenery/js/accessibility/voicing/nodes/VoicingText.js (revision faa4e9d6dbd874a6d3bd9a0b6dd4acabb54651b9)
+++ b/scenery/js/accessibility/voicing/nodes/VoicingText.js (date 1643062648054)
@@ -10,7 +10,7 @@
import merge from '../../../../../phet-core/js/merge.js';
import { ReadingBlock, ReadingBlockHighlight, scenery, Text } from '../../../imports.js';
-class VoicingText extends Text {
+class VoicingText extends ReadingBlock( Text ) {
/**
* @param {string} text
@@ -38,8 +38,6 @@
// unique highlight for non-interactive components
this.focusHighlight = new ReadingBlockHighlight( this );
- // voicing
- this.initializeReadingBlock();
this.mutate( options );
}
@@ -52,7 +50,5 @@
}
}
-ReadingBlock.compose( VoicingText );
-
scenery.register( 'VoicingText', VoicingText );
export default VoicingText;
Index: scenery/doc/accessibility/voicing.html
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scenery/doc/accessibility/voicing.html b/scenery/doc/accessibility/voicing.html
--- a/scenery/doc/accessibility/voicing.html (revision faa4e9d6dbd874a6d3bd9a0b6dd4acabb54651b9)
+++ b/scenery/doc/accessibility/voicing.html (date 1643066948363)
@@ -149,7 +149,7 @@
-
+
@@ -213,10 +213,10 @@
- Responses implemented with Voicing.js
- Voicing is implemented with a trait called Voicing.js
which can be composed with scenery's
+
Responses implemented with Voicing.ts
+ Voicing is implemented with a trait called Voicing.ts
which can be composed with scenery's
Node
. It provides the ability to set the various responses on the Node and then make a request to
- speak one or more of them. The API of Voicing.js is described in more detail later in this document.
+ speak one or more of them. The API of Voicing.ts is described in more detail later in this document.
Responses collected with responseCollector.js
@@ -227,8 +227,8 @@
and contains utility functions for assembling final Voicing content depending on the state of these Properties.
- Voicing.js API
- The following enumerates the Voicing.js API.
+ Voicing.ts API
+ The following enumerates the Voicing.ts API.
voicingNameResponse
A getter/setter for the {string|null}
name response for the Node.
@@ -302,7 +302,7 @@
voicingResponsePatternCollection
Sets the collection of patterns to use for voicingManager.collectResponses. This lets you control the
- order of Voicing.js responses, as well as customize punctuation and other formatting of the content.
+ order of Voicing.ts responses, as well as customize punctuation and other formatting of the content.
See ResponsePatternCollection.js
for more information and how to create your own collection
of patterns.
@@ -312,7 +312,7 @@
Code examples
Simple Example
- The following illustrates a basic example of using Voicing.js with a Node. Click the Rectangle
+
The following illustrates a basic example of using Voicing.ts with a Node. Click the Rectangle
to hear speech.