Skip to content

Commit

Permalink
add a11yDependencies, add usage in ISLCObjectNode, phetsims/gravity-f…
Browse files Browse the repository at this point in the history
  • Loading branch information
zepumph committed May 28, 2019
1 parent 4556554 commit c15a315
Showing 1 changed file with 52 additions and 7 deletions.
59 changes: 52 additions & 7 deletions js/accessibility/AccessibleValueHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ define( require => {
const inheritance = require( 'PHET_CORE/inheritance' );
const KeyboardUtil = require( 'SCENERY/accessibility/KeyboardUtil' );
const Node = require( 'SCENERY/nodes/Node' );
const Property = require( 'AXON/Property' );
const StringUtils = require( 'PHETCOMMON/util/StringUtils' );
const sun = require( 'SUN/sun' );
const SunConstants = require( 'SUN/SunConstants' );
Expand Down Expand Up @@ -123,6 +124,13 @@ define( require => {
*/
a11yCreateValueChangeAriaValueText: _.identity,

/**
* List the dependencies this Node's PDOM descriptions have. This should not include the valueProperty, but
* should list any Properties who's change should trigger description update for this Node.
* @type {Property[]}
*/
a11yDependencies: [],

/**
* By default there will be nothing special provided on focus, just the previous value set on Property change.
* If a specific aria-valuetext is desired when the interactive DOM element is focused, then use this option
Expand Down Expand Up @@ -224,9 +232,20 @@ define( require => {
// @private {function}
this.a11yMapValue = options.a11yMapValue;

// @private {function}
this.a11yValuePattern = options.a11yValuePattern;

// @private {function}
this.a11yCreateValueChangeAriaValueText = options.a11yCreateValueChangeAriaValueText;

// @private {Multilink}
this._dependenciesMultilink = null;

// @private - {null|function} see options for doc
this.a11yCreateOnFocusAriaValueText = options.a11yCreateOnFocusAriaValueText;

this.setA11yDependencies( options.a11yDependencies );

// listeners, must be unlinked in dispose
var enabledRangeObserver = ( enabledRange ) => {

Expand All @@ -243,16 +262,10 @@ define( require => {

// when the property changes, be sure to update the accessible input value and aria-valuetext which is read
// by assistive technology when the value changes
const valuePropertyListener = ( value, oldValue ) => {
const valuePropertyListener = () => {

const formattedValue = this.getA11yFormattedValue();

// create the final string from optional parameters. This looks messy, but in reality you can only supply
// the valuePattern OR the create function, so this works as an "either or" situation.
this.ariaValueText = StringUtils.fillIn( options.a11yValuePattern, {
value: options.a11yCreateValueChangeAriaValueText( formattedValue, value, oldValue )
} );

// set the aria-valuenow attribute in case the AT requires it to read the value correctly, some may
// fall back on this from aria-valuetext see
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-valuetext_attribute#Possible_effects_on_user_agents_and_assistive_technology
Expand All @@ -277,9 +290,41 @@ define( require => {
this._enabledRangeProperty.unlink( enabledRangeObserver );
this.removeInputListener( valueHandlerListener );
this._valueProperty.unlink( valuePropertyListener );
this._dependenciesMultilink && this._dependenciesMultilink.dispose();
};
},

/**
* There are some features of AccessibleValueHandler that support updating when more than just the valueProperty
* changes. Use this method to set the dependency Properties for this value handler. This will blow away the
* previous list (like Node.children).
* @public
* @param {Property[]} dependencies
*/
setA11yDependencies( dependencies ) {
assert && assert( Array.isArray( dependencies ) );
assert && assert( dependencies.indexOf( this._valueProperty ) === -1,
'The value Property is already a dependency, and does not need to be added to this list' );

// dispose the previous multilink, there is only one set of dependencies, though they can be overwritten.
this._dependenciesMultilink && this._dependenciesMultilink.dispose();

let oldValue = null;

this._dependenciesMultilink = Property.multilink( dependencies.concat( this._valueProperty ), () => {

const formattedValue = this.getA11yFormattedValue();

// create the final string from optional parameters. This looks messy, but in reality you can only supply
// the valuePattern OR the create function, so this works as an "either or" situation.
this.ariaValueText = StringUtils.fillIn( this.a11yValuePattern, {
value: this.a11yCreateValueChangeAriaValueText( formattedValue, this._valueProperty.value, oldValue )
} );

oldValue = this._valueProperty.value;
} );
},

/**
* @public
* Update the aria-valuetext for the next time that this element is focused.
Expand Down

0 comments on commit c15a315

Please sign in to comment.